SlideShare une entreprise Scribd logo
1  sur  46
Télécharger pour lire hors ligne
Learn BDD Playing Dice!



YOUR BEHAVIOR IS HAVE FUN



First Edition
Learn BDD Playing Dice!



YOUR BEHAVIOR IS HAVE FUN



First Edition



by Valério Farias de Carvalho
by Valério Farias de Carvalho. This document is licensed under Creative Commons 3.0 Attribution License.




First edition: July 2010



Valério Farias
http://www.valeriofarias.com
Twitter: @valeriofarias



Cover image from http://www.flickr.com/photos/missturner/
Learn BDD Playing Dice!




INTRODUCTION

Hello Ruby enthusiast! Hello BDD enthusiast! Welcome to this journey line by line, test by test, using the
Behaviour Driven Development technique in a interesting project: War Dice Simulation!. I wrote this tiny book
to learn BDD and RSpec for myself. I would want to start with a little example. And if was possible with a
funny example too. Then I thought: Why not playing dice! Why not playing war dice! Then there you are:
Learning BDD playing dice!

The app that we'll create together uses two classes: Dice and WarDice. The first chapter I start to construct
the RSpec file of Dice class and the Dice class simultaneously and step by step until all of the tests become
green.

The second chapter I go on with the WarDice class, that is a simulation of each dice of war game!

Finally, the third chapter I use the classes in a funny shoes application.

The philosophy of this book is to learn making funny things. In one word: Experimentation. Then I hope you
enjoy this simple but also instructive book.

The tests used in this book aren't a silver bullet. They are only a way between some others. How I told, I
made to learn RSpec. You can send suggests, clone the project, modify it and codify in other ways. Who
knows we'll playing together in the 2.0 version of this book :).

The complete source code of application you can download in https://github.com/valeriofarias/shoes-war-
dice/tree




                                                                                                                7
Learn BDD Playing Dice! - Your behavior is have fun


               Now, just read, codify, test, share and have fun!




8
Chapter 1: Making a Dice class using BDD




Chapter 1

            Making a Dice class using BDD


            GETTING STARTED

            Before start to programming let's install the essential packages. First install the rspec:

              gem install rspec

            If you want more usability, install the package zentest:

              gem install ZenTest

            Now install the package autotest-notification. This gem set the autotest (ZenTest) to send messages to
            software as Growl, LibNotify, and Snarl, displaying a window with the results. Read the readme file of the
            project to know how to install: http://github.com/carlosbrando/autotest-notification/. With this three gems, our
            journey become funny!


                                                                                                                               9
Learn BDD Playing Dice! - Your behavior is have fun


               To complete the bag, go to the shoes application page and read how to install in your operating system. Yes,
               shoes is very fun! We'll end our play with it. Access http://github.com/shoes/shoes/downloads or
               http://github.com/shoes/shoes. To learn how to use and execute shoes read the ebook Nobody knows Shoes
               available in http://github.com/shoes/shoes/downloads.

               Now let's start our travel test by test in the BDD world!


               CREATING THE RSPEC FILE

               First create the dice folder and the lib and spec folders inside it. Then you have to create the file dice_spec.rb
               inside the spec folder. Well! What you waiting! Let's write the first requirement in that file. Now we start to
               play!

                 require "rubygems"
                 require "spec"

                 require "lib/dice"

                 describe Dice do
                   it "should have numbers 1 to 6"
                 end

               To execute this test open the terminal end enter in the dice folder and use the test command:

                 cd dice
                 spec spec/dice_spec
                          /

               In our example with autotest, just digit the next command:




10
Chapter 1: Making a Dice class using BDD

  autospec

Now the test execute automatically every time that the files was saved. Come back to our example. The
output of this first test broke because we need create the Dice class in the lib/dice.rb file.

  spec --autospec spec/dice_spec.rb
                      /          rb
  ./spec/dice_spec.rb
   /    /          rb:6: uninitialized constant Dice (NameError)



WRITE THE DICE CLASS

To fix the initial error, just write the Dice class:

  class Dice
  end

Output: show the pending requirement.

  Pending:

  Dice should have only numbers 1 to 6 (Not Yet Implemented)
  ./spec/dice_spec.rb
   /    /          rb:7

  Finished in 0.04099 seconds

  1 example, 0 failures, 1 pending



THE NUMBERS IN THE DICE

The first requirement is to delimit the numbers of dice: 1 to 6:


                                                                                                        11
Learn BDD Playing Dice! - Your behavior is have fun

                 describe Dice do
                     it "should have only numbers 1 to 6" do
                       dice = Dice new
                              Dice.new
                       (1..6).should include dice.play )
                              should include(      play
                     end
                 end

               Output:

                 F

                 1)
                 NoMethodError in 'Dice should have only numbers 1 to 6'
                 undefined method `play' for #<Dice:0xb7b6986c>
                 ./spec/dice_spec.rb:9:

                 Finished in 0.073369 seconds

                 1 example, 1 failure



               CREATE THE PLAY METHOD IN DICE.RB

               To fix the previous failure let's write the play method:

                 class Dice
                   def play
                   end
                 end

               Output: still failure because the play method returns nil.




12
Chapter 1: Making a Dice class using BDD

  F

  1)
  'Dice should have only numbers 1 to 6' FAILED
  expected 1..6 to include nil
  ./spec/dice_spec.rb
   /    /          rb:9:

  Finished in 0.031104 seconds

  1 example, 1 failure



NUMBER OUTSIDE THE RANGE 1..6

Let's experiment to put a number outside of the range 1..6 to see what happens:

  class Dice
      def play
        10
      end
  end

Output: the test still failure because the number is outside the range.

  F

  1)
  'Dice should have numbers 1 to 6' FAILED
  expected 1..6 to include 10
  ./spec/dice_spec.rb
   /    /          rb:9:

  Finished in 0.03021 seconds




                                                                                                          13
Learn BDD Playing Dice! - Your behavior is have fun


                 1 example, 1 failure



               NUMBER INSIDE THE RANGE 1..6

               Now, let's put a number between 1-6, and finally the Dice class passes the test.

                 class Dice
                     def play
                       6
                     end
                 end

               Output:

                 .

                 Finished in 0.027648 seconds

                 1 example, 0 failures



               RANDOM NUMBERS

               For while it's ok. Now, let's work with the random numbers requirement. I'll put also some requirements that I
               remember, but not too much. I'll put x in the beginning of 'it' statement to rspec ignore then. this is just a trick
               ;).

                 require "rubygems"
                 require "spec"



14
Chapter 1: Making a Dice class using BDD


  require "lib/dice"

  describe Dice do
      it "should have only numbers 1 to 6" do
        dice = Dice new
               Dice.new
        (1..6).should include dice.play )
               should include(      play
      end

        # Three rand groups of 1000 numbers must    be different each other
        it "should show the numbers randomly" do
          dice = Dice new
                 Dice.new
          group1 = (1..1_000).collect dice.play
                              collect{       play   }
          group2 = (1..1_000).collect dice.play
                              collect{       play   }
          group3 = (1..1_000).collect dice.play
                              collect{       play   }
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should
          (group2 == group3).should be_false
                             should
        end

        xit "should store the last number after the dice was played."
        xit "should play the dice when dice object was initialized"
  end

Output:

  .F

  1)
  'Dice should show the numbers randomly' FAILED
  expected false got true
           false,
  ./spec/dice_spec.rb
   /    /          rb:18:

  Finished in 0.093321 seconds



                                                                                                       15
Learn BDD Playing Dice! - Your behavior is have fun


                 2 examples, 1 failure



               GENERATE RANDOM NUMBER AND REFACTORY

               Now I have to generate random numbers and also have to refactory the first requirement that limit the
               numbers 1 to 6. This requirement must be tested with a variety of numbers instead of only one how it's right
               now. To play a little bit with ruby, I'll modify also the require code to simplify the number of lines.

                 class Dice
                     def play
                       rand
                       rand(6)
                     end
                 end


                 %w{ rubygems spec lib/dice }.each {|lib| require lib}
                                              each

                 describe Dice do
                     it "should show only numbers 1 to 6" do
                       dice = Dice new
                              Dice.new
                       group = (1..1_000).collect dice.play }.join
                                          collect{      play   join
                       group.should_not be_nil
                             should_not
                       group.should_not be_empty
                             should_not
                             should_not include('-') # Negative numbers aren't permitted
                       group.should_not include
                       group.should_not include
                             should_not include('0')
                       group.should_not include
                             should_not include('7')
                       group.should_not include
                             should_not include('8')
                       group.should_not include
                             should_not include('9')
                     end




16
Chapter 1: Making a Dice class using BDD

        # Three rand groups of 1000 numbers must     be different each other
        it "should show the numbers randomly" do
          dice = Dice new
                 Dice.new
          group1 = (1..1_000).collect dice.play
                              collect{       play    }
          group2 = (1..1_000).collect dice.play
                              collect{       play    }
          group3 = (1..1_000).collect dice.play
                              collect{       play    }
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should
          (group2 == group3).should be_false
                             should
        end

        xit "should store the last number after the dice was played."
        xit "should play the dice when dice object was initialized"
  end

Output: rand(6) generate also zeros, the the test failure.

  F.

  1)
  'Dice should show only numbers 1 to 6' FAILED
  expected "4025132222510540002142312555235104432520522022430445143425254
  51533145101530430012510120055232441422435123332040350424441302405340420
  50050324205500223120330524430331015422350203015044053545205524012055023
  10100333140520435320541010244153022003403143022550340451124322335450431
  5335402445045511" not to include "0"
  ./spec/dice_spec.rb
   /    /          rb:10:

  Finished in 0.046589 seconds

  2 examples, 1 failure




                                                                                                        17
Learn BDD Playing Dice! - Your behavior is have fun


               FIXING THE RANDOM NUMBER FAILURE

               Finally let's put the command rand(6) + 1 to limit the range 1 to 6 and let's refactore the requirement of the
               range to use regexp. Now the test pass :).

                 class Dice
                     def play
                       rand
                       rand(6) + 1
                     end
                 end


                 %w{ rubygems spec lib/dice }.each {|lib| require lib}
                                              each

                 describe Dice do
                     it "should have only numbers 1 to 6" do
                       dice = Dice new
                              Dice.new
                       group = (1..1_000).collect dice.play }.join
                                          collect{      play  join
                       group.should match
                             should match(/^[1-6]*[1-6]$/)
                     end

                     # Three rand groups of 1000 numbers must      be different each other
                     it "should show the numbers randomly" do
                       dice = Dice new
                              Dice.new
                       group1 = (1..1_000).collect dice.play
                                           collect{       play     }
                       group2 = (1..1_000).collect dice.play
                                           collect{       play     }
                       group3 = (1..1_000).collect dice.play
                                           collect{       play     }
                       (group1 == group2).should be_false
                                          should
                       (group1 == group3).should be_false
                                          should
                       (group2 == group3).should be_false
                                          should
                     end

                     xit "should store the last number after the dice was played."




18
Chapter 1: Making a Dice class using BDD

        xit "should play the dice when dice object was initialized"
  end



STORE THE DICE NUMBER

Let's work in the next requirement: "should store the last number after the dice was played". I'll create the
method show_number and I'll put a constant to test pass.

  %w{rubygems spec lib/dice}.each {|lib| require lib}
                             each

  describe Dice do

        it "should have only numbers 1 to 6" do
          dice = Dice new
                 Dice.new
          group = (1..1_000).collect dice.play }.join
                             collect{      play  join
          group.should match
                should match(/^[1-6]*[1-6]$/)
        end

        # Three groups of 1000 random numbers must be different each other
        it "should show the numbers randomly" do
          dice = Dice new
                 Dice.new
          group1 = (1..1_000).collect dice.play }
                              collect{       play
          group2 = (1..1_000).collect dice.play }
                              collect{       play
          group3 = (1..1_000).collect dice.play }
                              collect{       play
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should
          (group2 == group3).should be_false
                             should
        end

        it "should store the last number after the dice was played." do
          dice = Dice new
                 Dice.new
          dice.play
               play



                                                                                                                19
Learn BDD Playing Dice! - Your behavior is have fun

                         dice.show_number to_s.should match
                              show_number.to_s should match(/^[1-6]*[1-6]$/)
                       end

                       xit "should play the dice when dice object was initialized."
                 end


                 class Dice
                     def play
                       rand
                       rand(6) + 1
                     end

                       def show_number
                         3
                       end
                 end



               CHANGING CONSTANTS BY VARIABLES

               This is an important rule in BDD. Now you can change the constant by a instance variable in the dice class.
               The test'll pass.

                 class Dice
                     def play
                       @number = rand
                                 rand(6) + 1
                     end

                       def show_number
                         @number
                       end
                 end




20
Chapter 1: Making a Dice class using BDD


PLAY THE DICE WHEN THE CLASS WAS INITIALIZED

Now I want that the dice play when it's initializing. The next test'll break.

  %w{rubygems spec lib/dice}.each {|lib| require lib}
                             each

  describe Dice do

       it "should have only numbers 1 to 6" do
         dice = Dice new
                Dice.new
         group = (1..1_000).collect dice.play }.join
                            collect{      play  join
         group.should match
               should match(/^[1-6]*[1-6]$/)
       end

       # Three groups of 1000 random numbers must be different each other
       it "should show the numbers randomly" do
         dice = Dice new
                Dice.new
         group1 = (1..1_000).collect dice.play }
                             collect{       play
         group2 = (1..1_000).collect dice.play }
                             collect{       play
         group3 = (1..1_000).collect dice.play }
                             collect{       play
         (group1 == group2).should be_false
                            should
         (group1 == group3).should be_false
                            should
         (group2 == group3).should be_false
                            should
       end

       it "should store the last number after the dice was played." do
         dice = Dice new
                Dice.new
         dice.play
              play
         dice.show_number to_s.should match
              show_number.to_s should match(/^[1-6]*[1-6]$/)
       end

       it "should play the dice when dice object was initialized." do
         Dice new.show_number to_s.should match
         Dice.new show_number.to_s should match(/^[1-6]*[1-6]$/)




                                                                                                            21
Learn BDD Playing Dice! - Your behavior is have fun

                        end

                 end

               Output:

                 ...F

                 1)
                 'Dice should play the dice when dice object was initialized.' FAILED
                 expected "" to match /^[1-6]*[1-6]$/
                 ./spec/dice_spec.rb
                  /    /          rb:29:

                 Finished in 0.12371 seconds

                 4 examples, 1 failure



               USING THE INITIALIZE METHOD

               Now I finalize the dice class putting the initialize method with a message for the play method. The test
               pass.

                 class Dice
                     def initialize
                       play
                     end

                        def play
                          @number = rand
                                    rand(6) + 1
                        end




22
Chapter 1: Making a Dice class using BDD

        def show_number
          @number
        end
  end



LET'S REFACTORY

Now I also can make a little refactory in the dice_spec.rb. I'll put a block before(:each) to simplify the code. I'll
make another refactory in the third requirement: "should store the last number after the dice was played".
Now he works with a lot of numbers. The logic is if the last number is stored then two groups of 100 numbers
stored are different each other.

  %w{rubygems spec lib/dice}.each {|lib| require lib}
                             each

  describe Dice do
      before :each do
      before(:each)
        @dice = Dice new
                Dice.new
      end

        it "should have only numbers 1 to 6" do
          group = (1..1_000).collect @dice.play }.join
                             collect{       play  join
          group.should match
                should match(/^[1-6]*[1-6]$/)
        end

        # Three groups of 1000 random numbers must be different each other
        it "should show the numbers randomly" do
          group1 = (1..1_000).collect @dice.play }
                              collect{       play
          group2 = (1..1_000).collect @dice.play }
                              collect{       play
          group3 = (1..1_000).collect @dice.play }
                              collect{       play
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should




                                                                                                                  23
Learn BDD Playing Dice! - Your behavior is have fun

                         (group2 == group3).should be_false
                                            should
                       end

                       it "should store the last number after the dice was played." do
                           group1 = (1..100).collect do
                                             collect
                             @dice.play
                                   play
                             @dice.show_number
                                   show_number
                           end
                           group2 = (1..100).collect do
                                             collect
                             @dice.play
                                   play
                             @dice.show_number
                                   show_number
                           end
                           (group1 == group2).should be_false
                                               should
                       end

                       it "should play the dice when dice object was initialized." do
                         @dice.show_number to_s.should match
                               show_number.to_s should match(/^[1-6]*[1-6]$/)
                       end

                 end



               PLAY WITH THE DICE CLASS

               Now that the class is finished. Let's play with it in the irb!

                 >>   require 'dice'
                 =>   true
                 >>   dice = Dice new
                             Dice.new
                 =>   #<Dice:0xb7a64188 @number=5>
                 >>   dice.show_number
                           show_number
                 =>   5




24
Chapter 1: Making a Dice class using BDD

  >> dice.class
          class
  => Dice

Using the dice only one time and abandon it

  >> Dice new.show_number
     Dice.new show_number
  => 2

Play the dice a lot of times:

  >> 20.times print dice.play }
        times{            play
  21636456135236136236=> 20

Three dice:

  >>   yellowdice = [Dice new, Dice new, Dice new]
                     Dice.new Dice.new Dice.new
  =>   [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>]
  >>   yellowdice.each |dice| puts dice.show_number }
                  each{                  show_number
  3
  5
  5
  =>   [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>]

Play again the same dice

  >> yellowdice.each |dice| puts dice.play }
                each{                  play
  5
  2
  5
  => [#<Dice:0xb7a3e3d4 @number=5>, #<Dice:0xb7a3e3ac @number=2>, #<Dice:0xb7a3e384 @number=5>]

What's the bigger value of the three dice of last play?



                                                                                                    25
Learn BDD Playing Dice! - Your behavior is have fun

                 >> puts yellowdice.collect |item| item.show_number }.max
                                    collect{            show_number   max
                 5
                 => nil

               And about the less value?

                 >> puts yellowdice.collect |item| item.show_number }.min
                                    collect{            show_number   min
                 2
                 => nil

               Wait. The last example I used 3 dice?!? Ahaaa! This looks like the dice of war game. Let's create the war
               game dice class in the next chapter.




26
Chapter 2: Reproducing the War Game Dice




Chapter 2

            Reproducing the War Game Dice


            DESCRIBING THE WAR GAME

            Now I finally finished the Dice class! But I want something more excitant! I want reproduce in a ruby class the
            dice of war game. That's right! That 6 dice. 3 red and 3 yellow that represent attack and defence respectively.

            I'll use two arrays: reddice and yellowdice to store the dice values. I remember now that the use of the dice
            depend on the army number of attacker and defender. But in this experiment I'll think only in the handling of
            dice in the game. Then the dice can be handle using 1, 2 or 3 red dice versus 1, 2 or 3 yellow dice. I'll have to
            compare the bigger red value with the bigger yellow value and consequently the next values using this logic
            (from bigger to less values). In draw case the yellow win. The red only win when the number was bigger then
            the yellow.

            Well, I think that's it. Let's work now!



                                                                                                                          27
Learn BDD Playing Dice! - Your behavior is have fun


               TESTING ARRAY COMPARISON

               Well, I remembered that we need to use array comparison in the dice of war game, but In my first test with
               array comparison I had problems. You can see this problem in the next test:

                 describe Array do
                     it "should be comparable" do
                       ([8,9,10] > [1,2,3]).should be_true
                                            should
                     end
                 end

               Output:

                 ....F

                 1)
                 NoMethodError in 'Array should be comparable'
                 undefined method `>' for [8, 9, 10]:Array
                 ./spec/dice_spec.rb:43:

                 Finished in 0.039464 seconds

                 5 examples, 1 failure



               INCLUDE COMPARABLE MODULE

               To solve the previous issue, just include the Comparable module in the dice.rb file. I'll put in a simplify form
               purposely to play with ruby possibilities :).

                 class Array; include Comparable; end



28
Chapter 2: Reproducing the War Game Dice


Now the test pass.


NUMBER OF DICE

Now I'll work on the first requirement: The attack and defence should use 1, 2 or 3 dice. I'll put intentionally
a number different of 1, 2, 3 to cause an error.

  describe Wardice do
      it "The attack and defence should use 1, 2 or 3 dice" do
        wardice = Wardice new(0, 3)
                  Wardice.new
        wardice.red to_s.should match
                red.to_s should match(/^[1-3]$/)
        wardice.yellow to_s.should match
                yellow.to_s should match(/^[1-3]$/)
      end

        it "Should compare from bigger to less values and save in array result"
  end


  class Wardice
      attr_reader :red :yellow
                   red,

        def initialize red, yellow)
            initialize(
          @red, @yellow = red, yellow
        end
  end

Output:

  'Wardice The attack and defence should use 1, 2 or 3 dice' FAILED
  expected "0" to match /^[1-3]$/
  ./spec/dice_spec.rb
   /    /          rb:50:



                                                                                                             29
Learn BDD Playing Dice! - Your behavior is have fun


                 Finished in 0.032203 seconds

                 8 examples, 1 failure, 2 pending



               SOLVING THE NUMBER ISSUE

               If the class was initialized with numbers differents of the range (1..3) then the variables will be filled with a
               rand number between the range. I'll make also a little refactory in the spec file to put a situation that a number
               of dice is correct. You can see below the solution.

                 class WarDice
                     attr_reader :red :yellow
                                  red,

                       def initialize red, yellow)
                           initialize(
                         @red, @yellow = red, yellow
                         @red = rand
                                rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                                     to_s.grep           empty?
                         @yellow = rand
                                   rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                                           to_s.grep            empty?
                       end
                 end

                 describe WarDice do
                     it "The attack and defence should use 1, 2 or 3 dice" do
                       wardice = Wardice new(0, 7)
                                 Wardice.new
                       wardice.red to_s.should match
                               red.to_s should match(/^[1-3]$/)
                       wardice.yellow to_s.should match
                               yellow.to_s should match(/^[1-3]$/)

                         wardice2 = Wardice new(2, 3)
                                    Wardice.new
                         wardice2.red should == 2
                                  red.should
                         wardice2.yellow should == 3
                                  yellow.should
                       end




30
Chapter 2: Reproducing the War Game Dice


        it "Should compare from bigger to less values and save in array result"
  end



DECREASE SORT ARRAY

This is a important requirement, but I remembered only now: wardice Should provide yellow and red dice
results with an array in decreasing sort. You can see the solution below:

  describe WarDice do
      it "The attack and defence should use 1, 2 or 3 dice" do
        wardice = WarDice new(0, 7)
                  WarDice.new
        wardice.red to_s.should match
                red.to_s should match(/^[1-3]$/)
        wardice.yellow to_s.should match
                yellow.to_s should match(/^[1-3]$/)

          wardice2 = WarDice new(2, 3)
                     WarDice.new
          wardice2.red should == 2
                   red.should
          wardice2.yellow should == 3
                   yellow.should
        end

        it "Should provide yellow and red dice results with an array in decreasing sort" do
          wardice = Wardice new(3, 3)
                    Wardice.new
          wardice.reddice is_a?(Array).should be_true
                  reddice.is_a?        should
          wardice.yellowdice is_a?(Array).should be_true
                  yellowdice.is_a?        should

          wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice
                  reddice.sort                  should            reddice
          wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice
                  yellowdice.sort                  should            yellowdice
        end

        it "Should compare from bigger to less values and save in array result"

  end



                                                                                                     31
Learn BDD Playing Dice! - Your behavior is have fun


                 class wardice
                     attr_reader :red :yellow :reddice :yellowdice
                                  red, yellow, reddice,

                       def initialize red, yellow)
                           initialize(
                         @red, @yellow = red, yellow
                         @red = rand
                                rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                                     to_s.grep           empty?
                         @yellow = rand
                                   rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                                           to_s.grep            empty?

                         @reddice = []
                         @yellowdice = []

                         @dice = Dice new
                                 Dice.new
                         @red.times
                              times{|row| @reddice[row] = [@dice.play }
                                                                 play]
                         @yellow.times |row| @yellowdice[row] = [@dice.play }
                                 times{                                 play]
                       end
                 end

               Output:

                 'wardice Should provide yellow and red dice results with an array in decreasing sort'   FAILED
                 expected: [[5], [2], [4]],
                      got: [[5], [4], [2]] (using ==
                                                  ==)
                 ./spec/dice_spec.rb
                  /    /          rb:63:

                 Finished in 0.035218 seconds

                 9 examples, 1 failure, 2 pending




32
Chapter 2: Reproducing the War Game Dice


SOLVING SORTING ARRAY ISSUE
  class WarDice
      attr_reader :red :yellow :reddice :yellowdice
                   red, yellow, reddice,

        def initialize red, yellow)
            initialize(
          @red, @yellow = red, yellow
          @red = rand
                 rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                      to_s.grep           empty?
          @yellow = rand
                    rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                            to_s.grep            empty?

          @reddice = []
          @yellowdice = []

          @dice = Dice new
                  Dice.new
          @red.times
               times{|row| @reddice[row] = [@dice.play }
                                                  play]
          @yellow.times |row| @yellowdice[row] = [@dice.play }
                  times{                                 play]

          @reddice.sort!
                   sort!{|x,y| y <=> x }
          @yellowdice.sort!
                      sort!{|x,y| y <=> x }
        end
  end

Now the test pass.


COMPARING VALUES

Let's work now in the last requirement: Should compare from bigger to less values and save in array
result

  describe Wardice do
      it "The attack and defence should use 1, 2 or 3 dice" do



                                                                                                      33
Learn BDD Playing Dice! - Your behavior is have fun

                         wardice = Wardice new(0, 7)
                                   Wardice.new
                         wardice.red to_s.should match
                                 red.to_s should match(/^[1-3]$/)
                         wardice.yellow to_s.should match
                                 yellow.to_s should match(/^[1-3]$/)

                         wardice2 = Wardice new(2, 3)
                                    Wardice.new
                         wardice2.red should == 2
                                  red.should
                         wardice2.yellow should == 3
                                  yellow.should
                       end

                       it "Should provide yellow and red dice results with an array in decreasing sort" do
                         wardice = Wardice new(3, 3)
                                   Wardice.new
                         wardice.reddice is_a?(Array).should be_true
                                 reddice.is_a?        should
                         wardice.yellowdice is_a?(Array).should be_true
                                 yellowdice.is_a?        should

                         wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice
                                 reddice.sort                  should            reddice
                         wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice
                                 yellowdice.sort                  should            yellowdice

                       end

                       it "Should compare from bigger to less values and save in array result" do
                         wardice = Wardice new(3, 2)
                                   Wardice.new
                         wardice.reddice first.should > wardice.reddice last
                                 reddice.first should           reddice.last
                         wardice.attack
                                 attack

                         wardice.result
                                 result[0].should == "Red Win" if wardice.reddice
                                           should                         reddice[0] > wardice.yellowdice
                                                                                               yellowdice[0]
                         wardice.result
                                 result[0].should == "Yellow Win" if wardice.reddice
                                           should                            reddice[0] <= wardice.yellowdice
                                                                                                   yellowdice[0]
                       end
                 end

               The final WarDice class:

                 class Wardice
                     attr_reader :red :yellow :reddice :yellowdice :result
                                  red, yellow, reddice, yellowdice,




34
Chapter 2: Reproducing the War Game Dice

      def initialize red, yellow)
          initialize(
        @red, @yellow = red, yellow
        @red = rand
               rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                    to_s.grep           empty?
        @yellow = rand
                  rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                          to_s.grep            empty?

        @reddice = []
        @yellowdice = []
        @result = []

        @dice = Dice new
                Dice.new
        @red.times
             times{|row| @reddice[row] = [@dice.play }
                                                play]
        @yellow.times |row| @yellowdice[row] = [@dice.play }
                times{                                 play]

        @reddice.sort!
                 sort!{|x, y| y <=> x }
        @yellowdice.sort!
                    sort!{|x, y| y <=> x }
      end

      def attack
        @reddice.each_with_index do |item, index|
                 each_with_index
          next if @yellowdice[index].nil?
                                     nil?
          reddice = item
          yellowdice = @yellowdice[index]

          if reddice > yellowdice
            @result << "Red Win"
          else
            @result << "Yellow Win"
          end
        end
      end
end




                                                                                                 35
Learn BDD Playing Dice! - Your behavior is have fun


               PLAY WITH THE WARDICE CLASS

               Open irb and write the next sequence:

                 >> require 'dice'
                 => true

               Initialize the WarDice class. The first parameter is the number of red dice and the second is the number of
               yellow dice:

                 >> wardice = WarDice new(2, 3)
                              WarDice.new
                 => #<WarDice:0xb7b0b410 @yellowdice=[[6], [1], [1]], @reddice=[[3], [1]], @dice=#<Dice:0xb7b0ae0c
                 @number=6>, yellow3, result["Yellow Win", "Yellow Win"], red2
                        = >

               Show numbers in yellow and red dice:

                 >>   puts wardice.reddice
                                   reddice
                 3
                 1
                 =>   nil
                 >>   puts wardice.yellowdice
                                   yellowdice
                 6
                 1
                 1
                 =>   nil

               Show result:

                 >> puts wardice.result
                                 result
                 Yellow Win
                 Yellow Win
                 => nil



36
Chapter 2: Reproducing the War Game Dice


All output in one command:

  >> war.reddice each_with_index{ |item, index| puts "Red:#{item} Yellow:#{war.yellowdice
         reddice.each_with_index                                               yellowdice[index]}
  - #{war.result
          result[index]}"}
  Red:3 Yellow:6 - Yellow Win
  Red:1 Yellow:1 - Yellow Win
  => [[3], [1]]

Now we have the tools to play. Then the next chapter we'll use this classes to make a nice graphic
application using Shoes.




                                                                                                      37
Learn BDD Playing Dice! - Your behavior is have fun




Chapter 3

               Playing dice with shoes


               A LITTLE TEST WITH DICE CLASS AND SHOES

               Now let's create a graphic interface using Shoes that will use the class WarDice. But first let's' make a simple
               test with the class Dice. You have to create a new file diceshoes.rb, then paste the code below inside it and
               save the file at the same directory of dice.rb file. Finally, execute it with shoes to see the result.

               Observe that I just included the dice.rb file with a require in the beginning of the code below:

                 require 'dice'
                 Shoes app :title => "Test with dice class", :width => 500, :height => 500 do
                 Shoes.app
                     background aliceblue

                     para "Welcome! This is an example using Dice class.", :weight => "bold"

                     dice = Dice new
                            Dice.new



38
Chapter 3: Playing dice with shoes


        # Print dice numbers with random colors
        1_000.times do
              times
          r, g, b = rand, rand, rand
          para dice.play :stroke => rgb **3, g**
                    play,            rgb(r**    **3, b**
                                                      **3), :size => "large"
        end
  end

Output:




THE WAR DICE SHOES CODE

Finally the last application. Copy the following code in a new file and save with the name wardiceshoes.rb in
the lib folder. I put some remarks across the code to facilitate the understanding. Have a nice experiment.


                                                                                                            39
Learn BDD Playing Dice! - Your behavior is have fun

                 require 'dice'

                 Shoes app :title => "Dice of War game", :width => 500, :height => 500 do
                 Shoes.app
                     background gradient black, teal )
                                gradient(

                     # List with number of red dice: 1, 2 or 3
                     para "Red", :stroke => tomato
                     @numberreddice = list_box :items => ["1", "2", "3"],
                       :width => 70, :choose => "3" do |list|
                     end

                     para " X ", :stroke => snow

                     # List with number of yellow dice: 1, 2 or 3
                     @numberyellowdice = list_box :items => ["1", "2", "3"],
                       :width => 70, :choose => "3" do |list|
                     end
                     para "Yellow", :stroke => yellow

                     # Define an aleatory position
                     @a = @b = @c = []

                      (40..200).step
                                step(10){ |x| @a << x }
                     (230..450).step
                                step(10){ |y| @b << y }
                     (80..450).step
                               step(10){ |z| @c << z }
                                            |

                     # Variables that will store values of wardice object
                     @reddice = @yellowdice = @resulttext = []

                     button "Attack", :width => 80 do

                       # Clear the screen
                       @dice.each |d| d.remove }
                             each{        remove
                       @resulttext.each |a| a.remove }
                                   each{         remove




40
Chapter 3: Playing dice with shoes


 # The wardice object is initializing
 wardice = WarDice new( @numberreddice.text to_i, @numberyellowdice.text to_i )
           WarDice.new                 text.to_i                    text.to_i
 @reddice    = wardice.reddice
                       reddice
 @yellowdice = wardice.yellowdice
                       yellowdice
 @result     = wardice.result
                       result

 # Every dice is drawn in random position
 @reddice.each |item| draw @a[rand
          each{        draw(    rand(@a.length
                                        length)], @c[rand
                                                     rand(@c.length
                                                             length)], item.to_s to_i, 1, true ) }
                                                                            to_s.to_i
 @yellowdice.each |item| draw @b[rand
             each{        draw(    rand(@b.length
                                           length)], @c[rand
                                                        rand(@c.length
                                                                length)], item.to_s to_i, 2, true )}
                                                                               to_s.to_i

end

button "Verify", :width => 80 do

 # Clear the screen
 @dice.each |d| d.remove }
       each{        remove
 @resulttext.each |a| a.remove }
             each{         remove

 # Initial position of dice
 leftyellow = 250
 leftred    = 150
 topred     = topyellow = 100

 # Every dice are drawn in a defined position
 @reddice.each do |item|
          each
   draw leftred, topred, item.to_s to_i, 1, false )
   draw(                       to_s.to_i
   topred += 100
 end

 @yellowdice.each do |item|
             each
   draw leftyellow, topyellow, item.to_s to_i, 2, false )
   draw(                            to_s.to_i
   topyellow += 100
 end




                                                                                            41
Learn BDD Playing Dice! - Your behavior is have fun


                       # Initial position of result
                       leftresult = 300
                       topresult = 80

                       # The results are drawn in defined positions
                       @result.each_with_index do |item, index|
                               each_with_index
                         @resulttext[index] = para item.to_s :stroke => snow, :top => topresult, :left => leftresult
                                                        to_s,
                         topresult += 100
                       end

                     end


                     # Method draw was based in the Pretty Dice project written by Ed Heil
                     @dice = []

                     def draw left, top, number, color, rotate )
                         draw(

                           imagewidth = 60
                           imageheight = 60

                           i = image imagewidth, imageheight,
                               image(
                               :top => top - imagewidth / 2,
                               :left => left - imagewidth / 2,
                               :shadow => 10, :center => true ) do

                               if color == 1
                                 strokecolor = red
                                 fillrectanglecolor = tomato
                                 filldotscolor = darkred
                               else
                                 strokecolor = yellow
                                 fillrectanglecolor = lightgoldenrodyellow




42
Chapter 3: Playing dice with shoes

  filldotscolor = chocolate
end

sw = 1
strokewidth sw
stroke strokecolor

fill fillrectanglecolor

inset = 2
inset2 = 8

rect inset, inset, imagewidth-inset-sw, imageheight-inset-sw, 10 )
rect(                        -     -               -     -

fill filldotscolor

ovalradius = 10
low = inset2
high = imagewidth - inset2 - ovalradius
mid = ( imagewidth - ovalradius ) / 2

oval mid, mid, ovalradius ) if number % 2 == 1
oval(

if number > 1
  oval low, low, ovalradius )
  oval(
  oval high, high, ovalradius )
  oval(
end

if number > 3
  oval low, high, ovalradius )
  oval(
  oval high, low, ovalradius )
  oval(
end

if number > 5




                                                                                     43
Learn BDD Playing Dice! - Your behavior is have fun

                                   oval mid, low, ovalradius )
                                   oval(
                                   oval mid, high, ovalradius )
                                   oval(
                                 end

                             end # end of image block

                             i.rotate rand 359 ) ) if rotate
                               rotate( rand(

                             @dice << i

                       end

                 end



               PLAYING WITH WAR DICE SHOES APP

               Below you can see the War Dice app in action. You must choose the number of red and yellow dice in
               respective list box. Then click in Attack button to play dice. Now just have fun!




44
Chapter 3: Playing dice with shoes




Now click in verify button to know who wins!




                                                                              45
Learn BDD Playing Dice! - Your behavior is have fun




46

Contenu connexe

En vedette

AP Style: Learn It, Live It, Love It
AP Style: Learn It, Live It, Love ItAP Style: Learn It, Live It, Love It
AP Style: Learn It, Live It, Love ItMaria Fogliasso
 
Ayrshire Get Trading Online Slides
Ayrshire Get Trading Online SlidesAyrshire Get Trading Online Slides
Ayrshire Get Trading Online SlidesVenda-PayPal-Webjam
 
Surrey Chamber Of Commerce Online Trading Slides
Surrey Chamber Of Commerce   Online Trading SlidesSurrey Chamber Of Commerce   Online Trading Slides
Surrey Chamber Of Commerce Online Trading SlidesVenda-PayPal-Webjam
 
East Cheshire Get Trading Online Slidedeck
East Cheshire Get Trading Online SlidedeckEast Cheshire Get Trading Online Slidedeck
East Cheshire Get Trading Online SlidedeckVenda-PayPal-Webjam
 
Dorset Chamber Get Trading Online Slides
Dorset Chamber   Get Trading Online SlidesDorset Chamber   Get Trading Online Slides
Dorset Chamber Get Trading Online SlidesVenda-PayPal-Webjam
 
North Staffordshire Chamber Get Trading Online Slides
North Staffordshire Chamber   Get Trading Online SlidesNorth Staffordshire Chamber   Get Trading Online Slides
North Staffordshire Chamber Get Trading Online SlidesVenda-PayPal-Webjam
 
Social Media in the Business Environment
Social Media in the Business EnvironmentSocial Media in the Business Environment
Social Media in the Business EnvironmentMaria Fogliasso
 
happy new day (C) onemusicdesign
happy new day (C) onemusicdesignhappy new day (C) onemusicdesign
happy new day (C) onemusicdesignonemusicdesign
 

En vedette (8)

AP Style: Learn It, Live It, Love It
AP Style: Learn It, Live It, Love ItAP Style: Learn It, Live It, Love It
AP Style: Learn It, Live It, Love It
 
Ayrshire Get Trading Online Slides
Ayrshire Get Trading Online SlidesAyrshire Get Trading Online Slides
Ayrshire Get Trading Online Slides
 
Surrey Chamber Of Commerce Online Trading Slides
Surrey Chamber Of Commerce   Online Trading SlidesSurrey Chamber Of Commerce   Online Trading Slides
Surrey Chamber Of Commerce Online Trading Slides
 
East Cheshire Get Trading Online Slidedeck
East Cheshire Get Trading Online SlidedeckEast Cheshire Get Trading Online Slidedeck
East Cheshire Get Trading Online Slidedeck
 
Dorset Chamber Get Trading Online Slides
Dorset Chamber   Get Trading Online SlidesDorset Chamber   Get Trading Online Slides
Dorset Chamber Get Trading Online Slides
 
North Staffordshire Chamber Get Trading Online Slides
North Staffordshire Chamber   Get Trading Online SlidesNorth Staffordshire Chamber   Get Trading Online Slides
North Staffordshire Chamber Get Trading Online Slides
 
Social Media in the Business Environment
Social Media in the Business EnvironmentSocial Media in the Business Environment
Social Media in the Business Environment
 
happy new day (C) onemusicdesign
happy new day (C) onemusicdesignhappy new day (C) onemusicdesign
happy new day (C) onemusicdesign
 

Similaire à Learn bdd-playing-dice-book

Applying RSpec Best Practises
Applying RSpec Best PractisesApplying RSpec Best Practises
Applying RSpec Best PractisesNeil Henegan
 
Ruby Rails Overview
Ruby Rails OverviewRuby Rails Overview
Ruby Rails OverviewNetguru
 
I have another assignment due for an advance java programming class .pdf
I have another assignment due for an advance java programming class .pdfI have another assignment due for an advance java programming class .pdf
I have another assignment due for an advance java programming class .pdfFORTUNE2505
 
SKY3DS Homebrews on 9.6 3DS?
SKY3DS Homebrews on 9.6 3DS?SKY3DS Homebrews on 9.6 3DS?
SKY3DS Homebrews on 9.6 3DS?bizarrephilosop88
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at WorkErin Dees
 
Controlling Project Size for Student/Hobby Videogame Development
Controlling Project Size for Student/Hobby Videogame DevelopmentControlling Project Size for Student/Hobby Videogame Development
Controlling Project Size for Student/Hobby Videogame DevelopmentChris DeLeon
 
ontents · Introduction· Objectives·.docx
ontents  ·      Introduction·      Objectives·.docxontents  ·      Introduction·      Objectives·.docx
ontents · Introduction· Objectives·.docxcherishwinsland
 
Universe Ball Anthology #1 (Sample)
Universe Ball Anthology #1 (Sample)Universe Ball Anthology #1 (Sample)
Universe Ball Anthology #1 (Sample)DylanAssed
 
how to hack with pack and unpack
how to hack with pack and unpackhow to hack with pack and unpack
how to hack with pack and unpackDavid Lowe
 
Boxen: How to Manage an Army of Laptops
Boxen: How to Manage an Army of LaptopsBoxen: How to Manage an Army of Laptops
Boxen: How to Manage an Army of LaptopsPuppet
 
Solution to warsaw's crackme1.1
Solution to warsaw's crackme1.1Solution to warsaw's crackme1.1
Solution to warsaw's crackme1.1Aodrulez
 
Solucionario de int3pids del I Wargame de Sbd - 2011
Solucionario de int3pids del I Wargame de Sbd - 2011Solucionario de int3pids del I Wargame de Sbd - 2011
Solucionario de int3pids del I Wargame de Sbd - 2011secbydefault
 
2.4 notes b
2.4 notes b2.4 notes b
2.4 notes bmbetzel
 
10 open source / homebrew games for handhelds in 10 minutess
10 open source / homebrew games for handhelds in 10 minutess10 open source / homebrew games for handhelds in 10 minutess
10 open source / homebrew games for handhelds in 10 minutessRain Ashford
 
Most asked JAVA Interview Questions & Answers.
Most asked JAVA Interview Questions & Answers.Most asked JAVA Interview Questions & Answers.
Most asked JAVA Interview Questions & Answers.Questpond
 
Creating your own Abstract Processor
Creating your own Abstract ProcessorCreating your own Abstract Processor
Creating your own Abstract ProcessorAodrulez
 

Similaire à Learn bdd-playing-dice-book (19)

Applying RSpec Best Practises
Applying RSpec Best PractisesApplying RSpec Best Practises
Applying RSpec Best Practises
 
Ruby Rails Overview
Ruby Rails OverviewRuby Rails Overview
Ruby Rails Overview
 
I have another assignment due for an advance java programming class .pdf
I have another assignment due for an advance java programming class .pdfI have another assignment due for an advance java programming class .pdf
I have another assignment due for an advance java programming class .pdf
 
SKY3DS Homebrews on 9.6 3DS?
SKY3DS Homebrews on 9.6 3DS?SKY3DS Homebrews on 9.6 3DS?
SKY3DS Homebrews on 9.6 3DS?
 
Programmers guide
Programmers guideProgrammers guide
Programmers guide
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at Work
 
Controlling Project Size for Student/Hobby Videogame Development
Controlling Project Size for Student/Hobby Videogame DevelopmentControlling Project Size for Student/Hobby Videogame Development
Controlling Project Size for Student/Hobby Videogame Development
 
Pong
PongPong
Pong
 
ontents · Introduction· Objectives·.docx
ontents  ·      Introduction·      Objectives·.docxontents  ·      Introduction·      Objectives·.docx
ontents · Introduction· Objectives·.docx
 
Universe Ball Anthology #1 (Sample)
Universe Ball Anthology #1 (Sample)Universe Ball Anthology #1 (Sample)
Universe Ball Anthology #1 (Sample)
 
how to hack with pack and unpack
how to hack with pack and unpackhow to hack with pack and unpack
how to hack with pack and unpack
 
Boxen: How to Manage an Army of Laptops
Boxen: How to Manage an Army of LaptopsBoxen: How to Manage an Army of Laptops
Boxen: How to Manage an Army of Laptops
 
Solution to warsaw's crackme1.1
Solution to warsaw's crackme1.1Solution to warsaw's crackme1.1
Solution to warsaw's crackme1.1
 
Solucionario de int3pids del I Wargame de Sbd - 2011
Solucionario de int3pids del I Wargame de Sbd - 2011Solucionario de int3pids del I Wargame de Sbd - 2011
Solucionario de int3pids del I Wargame de Sbd - 2011
 
2.4 notes b
2.4 notes b2.4 notes b
2.4 notes b
 
10 open source / homebrew games for handhelds in 10 minutess
10 open source / homebrew games for handhelds in 10 minutess10 open source / homebrew games for handhelds in 10 minutess
10 open source / homebrew games for handhelds in 10 minutess
 
A mazing Game
A mazing GameA mazing Game
A mazing Game
 
Most asked JAVA Interview Questions & Answers.
Most asked JAVA Interview Questions & Answers.Most asked JAVA Interview Questions & Answers.
Most asked JAVA Interview Questions & Answers.
 
Creating your own Abstract Processor
Creating your own Abstract ProcessorCreating your own Abstract Processor
Creating your own Abstract Processor
 

Dernier

Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Disha Kariya
 
APM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAPM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAssociation for Project Management
 
Unit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptxUnit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptxVishalSingh1417
 
Introduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The BasicsIntroduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The BasicsTechSoup
 
Z Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot GraphZ Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot GraphThiyagu K
 
Application orientated numerical on hev.ppt
Application orientated numerical on hev.pptApplication orientated numerical on hev.ppt
Application orientated numerical on hev.pptRamjanShidvankar
 
Seal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptxSeal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptxnegromaestrong
 
Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104misteraugie
 
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in DelhiRussian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhikauryashika82
 
Paris 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityParis 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityGeoBlogs
 
microwave assisted reaction. General introduction
microwave assisted reaction. General introductionmicrowave assisted reaction. General introduction
microwave assisted reaction. General introductionMaksud Ahmed
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeThiyagu K
 
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...Shubhangi Sonawane
 
PROCESS RECORDING FORMAT.docx
PROCESS      RECORDING        FORMAT.docxPROCESS      RECORDING        FORMAT.docx
PROCESS RECORDING FORMAT.docxPoojaSen20
 
Unit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxUnit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxVishalSingh1417
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDThiyagu K
 
Key note speaker Neum_Admir Softic_ENG.pdf
Key note speaker Neum_Admir Softic_ENG.pdfKey note speaker Neum_Admir Softic_ENG.pdf
Key note speaker Neum_Admir Softic_ENG.pdfAdmir Softic
 
psychiatric nursing HISTORY COLLECTION .docx
psychiatric  nursing HISTORY  COLLECTION  .docxpsychiatric  nursing HISTORY  COLLECTION  .docx
psychiatric nursing HISTORY COLLECTION .docxPoojaSen20
 

Dernier (20)

Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..Sports & Fitness Value Added Course FY..
Sports & Fitness Value Added Course FY..
 
Advance Mobile Application Development class 07
Advance Mobile Application Development class 07Advance Mobile Application Development class 07
Advance Mobile Application Development class 07
 
APM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAPM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across Sectors
 
Unit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptxUnit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptx
 
Introduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The BasicsIntroduction to Nonprofit Accounting: The Basics
Introduction to Nonprofit Accounting: The Basics
 
Z Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot GraphZ Score,T Score, Percential Rank and Box Plot Graph
Z Score,T Score, Percential Rank and Box Plot Graph
 
Application orientated numerical on hev.ppt
Application orientated numerical on hev.pptApplication orientated numerical on hev.ppt
Application orientated numerical on hev.ppt
 
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
 
Seal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptxSeal of Good Local Governance (SGLG) 2024Final.pptx
Seal of Good Local Governance (SGLG) 2024Final.pptx
 
Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104
 
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in DelhiRussian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
 
Paris 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityParis 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activity
 
microwave assisted reaction. General introduction
microwave assisted reaction. General introductionmicrowave assisted reaction. General introduction
microwave assisted reaction. General introduction
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and Mode
 
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
 
PROCESS RECORDING FORMAT.docx
PROCESS      RECORDING        FORMAT.docxPROCESS      RECORDING        FORMAT.docx
PROCESS RECORDING FORMAT.docx
 
Unit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxUnit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptx
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SD
 
Key note speaker Neum_Admir Softic_ENG.pdf
Key note speaker Neum_Admir Softic_ENG.pdfKey note speaker Neum_Admir Softic_ENG.pdf
Key note speaker Neum_Admir Softic_ENG.pdf
 
psychiatric nursing HISTORY COLLECTION .docx
psychiatric  nursing HISTORY  COLLECTION  .docxpsychiatric  nursing HISTORY  COLLECTION  .docx
psychiatric nursing HISTORY COLLECTION .docx
 

Learn bdd-playing-dice-book

  • 1.
  • 2.
  • 3. Learn BDD Playing Dice! YOUR BEHAVIOR IS HAVE FUN First Edition
  • 4.
  • 5. Learn BDD Playing Dice! YOUR BEHAVIOR IS HAVE FUN First Edition by Valério Farias de Carvalho
  • 6. by Valério Farias de Carvalho. This document is licensed under Creative Commons 3.0 Attribution License. First edition: July 2010 Valério Farias http://www.valeriofarias.com Twitter: @valeriofarias Cover image from http://www.flickr.com/photos/missturner/
  • 7. Learn BDD Playing Dice! INTRODUCTION Hello Ruby enthusiast! Hello BDD enthusiast! Welcome to this journey line by line, test by test, using the Behaviour Driven Development technique in a interesting project: War Dice Simulation!. I wrote this tiny book to learn BDD and RSpec for myself. I would want to start with a little example. And if was possible with a funny example too. Then I thought: Why not playing dice! Why not playing war dice! Then there you are: Learning BDD playing dice! The app that we'll create together uses two classes: Dice and WarDice. The first chapter I start to construct the RSpec file of Dice class and the Dice class simultaneously and step by step until all of the tests become green. The second chapter I go on with the WarDice class, that is a simulation of each dice of war game! Finally, the third chapter I use the classes in a funny shoes application. The philosophy of this book is to learn making funny things. In one word: Experimentation. Then I hope you enjoy this simple but also instructive book. The tests used in this book aren't a silver bullet. They are only a way between some others. How I told, I made to learn RSpec. You can send suggests, clone the project, modify it and codify in other ways. Who knows we'll playing together in the 2.0 version of this book :). The complete source code of application you can download in https://github.com/valeriofarias/shoes-war- dice/tree 7
  • 8. Learn BDD Playing Dice! - Your behavior is have fun Now, just read, codify, test, share and have fun! 8
  • 9. Chapter 1: Making a Dice class using BDD Chapter 1 Making a Dice class using BDD GETTING STARTED Before start to programming let's install the essential packages. First install the rspec: gem install rspec If you want more usability, install the package zentest: gem install ZenTest Now install the package autotest-notification. This gem set the autotest (ZenTest) to send messages to software as Growl, LibNotify, and Snarl, displaying a window with the results. Read the readme file of the project to know how to install: http://github.com/carlosbrando/autotest-notification/. With this three gems, our journey become funny! 9
  • 10. Learn BDD Playing Dice! - Your behavior is have fun To complete the bag, go to the shoes application page and read how to install in your operating system. Yes, shoes is very fun! We'll end our play with it. Access http://github.com/shoes/shoes/downloads or http://github.com/shoes/shoes. To learn how to use and execute shoes read the ebook Nobody knows Shoes available in http://github.com/shoes/shoes/downloads. Now let's start our travel test by test in the BDD world! CREATING THE RSPEC FILE First create the dice folder and the lib and spec folders inside it. Then you have to create the file dice_spec.rb inside the spec folder. Well! What you waiting! Let's write the first requirement in that file. Now we start to play! require "rubygems" require "spec" require "lib/dice" describe Dice do it "should have numbers 1 to 6" end To execute this test open the terminal end enter in the dice folder and use the test command: cd dice spec spec/dice_spec / In our example with autotest, just digit the next command: 10
  • 11. Chapter 1: Making a Dice class using BDD autospec Now the test execute automatically every time that the files was saved. Come back to our example. The output of this first test broke because we need create the Dice class in the lib/dice.rb file. spec --autospec spec/dice_spec.rb / rb ./spec/dice_spec.rb / / rb:6: uninitialized constant Dice (NameError) WRITE THE DICE CLASS To fix the initial error, just write the Dice class: class Dice end Output: show the pending requirement. Pending: Dice should have only numbers 1 to 6 (Not Yet Implemented) ./spec/dice_spec.rb / / rb:7 Finished in 0.04099 seconds 1 example, 0 failures, 1 pending THE NUMBERS IN THE DICE The first requirement is to delimit the numbers of dice: 1 to 6: 11
  • 12. Learn BDD Playing Dice! - Your behavior is have fun describe Dice do it "should have only numbers 1 to 6" do dice = Dice new Dice.new (1..6).should include dice.play ) should include( play end end Output: F 1) NoMethodError in 'Dice should have only numbers 1 to 6' undefined method `play' for #<Dice:0xb7b6986c> ./spec/dice_spec.rb:9: Finished in 0.073369 seconds 1 example, 1 failure CREATE THE PLAY METHOD IN DICE.RB To fix the previous failure let's write the play method: class Dice def play end end Output: still failure because the play method returns nil. 12
  • 13. Chapter 1: Making a Dice class using BDD F 1) 'Dice should have only numbers 1 to 6' FAILED expected 1..6 to include nil ./spec/dice_spec.rb / / rb:9: Finished in 0.031104 seconds 1 example, 1 failure NUMBER OUTSIDE THE RANGE 1..6 Let's experiment to put a number outside of the range 1..6 to see what happens: class Dice def play 10 end end Output: the test still failure because the number is outside the range. F 1) 'Dice should have numbers 1 to 6' FAILED expected 1..6 to include 10 ./spec/dice_spec.rb / / rb:9: Finished in 0.03021 seconds 13
  • 14. Learn BDD Playing Dice! - Your behavior is have fun 1 example, 1 failure NUMBER INSIDE THE RANGE 1..6 Now, let's put a number between 1-6, and finally the Dice class passes the test. class Dice def play 6 end end Output: . Finished in 0.027648 seconds 1 example, 0 failures RANDOM NUMBERS For while it's ok. Now, let's work with the random numbers requirement. I'll put also some requirements that I remember, but not too much. I'll put x in the beginning of 'it' statement to rspec ignore then. this is just a trick ;). require "rubygems" require "spec" 14
  • 15. Chapter 1: Making a Dice class using BDD require "lib/dice" describe Dice do it "should have only numbers 1 to 6" do dice = Dice new Dice.new (1..6).should include dice.play ) should include( play end # Three rand groups of 1000 numbers must be different each other it "should show the numbers randomly" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play collect{ play } group2 = (1..1_000).collect dice.play collect{ play } group3 = (1..1_000).collect dice.play collect{ play } (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end xit "should store the last number after the dice was played." xit "should play the dice when dice object was initialized" end Output: .F 1) 'Dice should show the numbers randomly' FAILED expected false got true false, ./spec/dice_spec.rb / / rb:18: Finished in 0.093321 seconds 15
  • 16. Learn BDD Playing Dice! - Your behavior is have fun 2 examples, 1 failure GENERATE RANDOM NUMBER AND REFACTORY Now I have to generate random numbers and also have to refactory the first requirement that limit the numbers 1 to 6. This requirement must be tested with a variety of numbers instead of only one how it's right now. To play a little bit with ruby, I'll modify also the require code to simplify the number of lines. class Dice def play rand rand(6) end end %w{ rubygems spec lib/dice }.each {|lib| require lib} each describe Dice do it "should show only numbers 1 to 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should_not be_nil should_not group.should_not be_empty should_not should_not include('-') # Negative numbers aren't permitted group.should_not include group.should_not include should_not include('0') group.should_not include should_not include('7') group.should_not include should_not include('8') group.should_not include should_not include('9') end 16
  • 17. Chapter 1: Making a Dice class using BDD # Three rand groups of 1000 numbers must be different each other it "should show the numbers randomly" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play collect{ play } group2 = (1..1_000).collect dice.play collect{ play } group3 = (1..1_000).collect dice.play collect{ play } (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end xit "should store the last number after the dice was played." xit "should play the dice when dice object was initialized" end Output: rand(6) generate also zeros, the the test failure. F. 1) 'Dice should show only numbers 1 to 6' FAILED expected "4025132222510540002142312555235104432520522022430445143425254 51533145101530430012510120055232441422435123332040350424441302405340420 50050324205500223120330524430331015422350203015044053545205524012055023 10100333140520435320541010244153022003403143022550340451124322335450431 5335402445045511" not to include "0" ./spec/dice_spec.rb / / rb:10: Finished in 0.046589 seconds 2 examples, 1 failure 17
  • 18. Learn BDD Playing Dice! - Your behavior is have fun FIXING THE RANDOM NUMBER FAILURE Finally let's put the command rand(6) + 1 to limit the range 1 to 6 and let's refactore the requirement of the range to use regexp. Now the test pass :). class Dice def play rand rand(6) + 1 end end %w{ rubygems spec lib/dice }.each {|lib| require lib} each describe Dice do it "should have only numbers 1 to 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Three rand groups of 1000 numbers must be different each other it "should show the numbers randomly" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play collect{ play } group2 = (1..1_000).collect dice.play collect{ play } group3 = (1..1_000).collect dice.play collect{ play } (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end xit "should store the last number after the dice was played." 18
  • 19. Chapter 1: Making a Dice class using BDD xit "should play the dice when dice object was initialized" end STORE THE DICE NUMBER Let's work in the next requirement: "should store the last number after the dice was played". I'll create the method show_number and I'll put a constant to test pass. %w{rubygems spec lib/dice}.each {|lib| require lib} each describe Dice do it "should have only numbers 1 to 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Three groups of 1000 random numbers must be different each other it "should show the numbers randomly" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end it "should store the last number after the dice was played." do dice = Dice new Dice.new dice.play play 19
  • 20. Learn BDD Playing Dice! - Your behavior is have fun dice.show_number to_s.should match show_number.to_s should match(/^[1-6]*[1-6]$/) end xit "should play the dice when dice object was initialized." end class Dice def play rand rand(6) + 1 end def show_number 3 end end CHANGING CONSTANTS BY VARIABLES This is an important rule in BDD. Now you can change the constant by a instance variable in the dice class. The test'll pass. class Dice def play @number = rand rand(6) + 1 end def show_number @number end end 20
  • 21. Chapter 1: Making a Dice class using BDD PLAY THE DICE WHEN THE CLASS WAS INITIALIZED Now I want that the dice play when it's initializing. The next test'll break. %w{rubygems spec lib/dice}.each {|lib| require lib} each describe Dice do it "should have only numbers 1 to 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Three groups of 1000 random numbers must be different each other it "should show the numbers randomly" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end it "should store the last number after the dice was played." do dice = Dice new Dice.new dice.play play dice.show_number to_s.should match show_number.to_s should match(/^[1-6]*[1-6]$/) end it "should play the dice when dice object was initialized." do Dice new.show_number to_s.should match Dice.new show_number.to_s should match(/^[1-6]*[1-6]$/) 21
  • 22. Learn BDD Playing Dice! - Your behavior is have fun end end Output: ...F 1) 'Dice should play the dice when dice object was initialized.' FAILED expected "" to match /^[1-6]*[1-6]$/ ./spec/dice_spec.rb / / rb:29: Finished in 0.12371 seconds 4 examples, 1 failure USING THE INITIALIZE METHOD Now I finalize the dice class putting the initialize method with a message for the play method. The test pass. class Dice def initialize play end def play @number = rand rand(6) + 1 end 22
  • 23. Chapter 1: Making a Dice class using BDD def show_number @number end end LET'S REFACTORY Now I also can make a little refactory in the dice_spec.rb. I'll put a block before(:each) to simplify the code. I'll make another refactory in the third requirement: "should store the last number after the dice was played". Now he works with a lot of numbers. The logic is if the last number is stored then two groups of 100 numbers stored are different each other. %w{rubygems spec lib/dice}.each {|lib| require lib} each describe Dice do before :each do before(:each) @dice = Dice new Dice.new end it "should have only numbers 1 to 6" do group = (1..1_000).collect @dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Three groups of 1000 random numbers must be different each other it "should show the numbers randomly" do group1 = (1..1_000).collect @dice.play } collect{ play group2 = (1..1_000).collect @dice.play } collect{ play group3 = (1..1_000).collect @dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should 23
  • 24. Learn BDD Playing Dice! - Your behavior is have fun (group2 == group3).should be_false should end it "should store the last number after the dice was played." do group1 = (1..100).collect do collect @dice.play play @dice.show_number show_number end group2 = (1..100).collect do collect @dice.play play @dice.show_number show_number end (group1 == group2).should be_false should end it "should play the dice when dice object was initialized." do @dice.show_number to_s.should match show_number.to_s should match(/^[1-6]*[1-6]$/) end end PLAY WITH THE DICE CLASS Now that the class is finished. Let's play with it in the irb! >> require 'dice' => true >> dice = Dice new Dice.new => #<Dice:0xb7a64188 @number=5> >> dice.show_number show_number => 5 24
  • 25. Chapter 1: Making a Dice class using BDD >> dice.class class => Dice Using the dice only one time and abandon it >> Dice new.show_number Dice.new show_number => 2 Play the dice a lot of times: >> 20.times print dice.play } times{ play 21636456135236136236=> 20 Three dice: >> yellowdice = [Dice new, Dice new, Dice new] Dice.new Dice.new Dice.new => [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>] >> yellowdice.each |dice| puts dice.show_number } each{ show_number 3 5 5 => [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>] Play again the same dice >> yellowdice.each |dice| puts dice.play } each{ play 5 2 5 => [#<Dice:0xb7a3e3d4 @number=5>, #<Dice:0xb7a3e3ac @number=2>, #<Dice:0xb7a3e384 @number=5>] What's the bigger value of the three dice of last play? 25
  • 26. Learn BDD Playing Dice! - Your behavior is have fun >> puts yellowdice.collect |item| item.show_number }.max collect{ show_number max 5 => nil And about the less value? >> puts yellowdice.collect |item| item.show_number }.min collect{ show_number min 2 => nil Wait. The last example I used 3 dice?!? Ahaaa! This looks like the dice of war game. Let's create the war game dice class in the next chapter. 26
  • 27. Chapter 2: Reproducing the War Game Dice Chapter 2 Reproducing the War Game Dice DESCRIBING THE WAR GAME Now I finally finished the Dice class! But I want something more excitant! I want reproduce in a ruby class the dice of war game. That's right! That 6 dice. 3 red and 3 yellow that represent attack and defence respectively. I'll use two arrays: reddice and yellowdice to store the dice values. I remember now that the use of the dice depend on the army number of attacker and defender. But in this experiment I'll think only in the handling of dice in the game. Then the dice can be handle using 1, 2 or 3 red dice versus 1, 2 or 3 yellow dice. I'll have to compare the bigger red value with the bigger yellow value and consequently the next values using this logic (from bigger to less values). In draw case the yellow win. The red only win when the number was bigger then the yellow. Well, I think that's it. Let's work now! 27
  • 28. Learn BDD Playing Dice! - Your behavior is have fun TESTING ARRAY COMPARISON Well, I remembered that we need to use array comparison in the dice of war game, but In my first test with array comparison I had problems. You can see this problem in the next test: describe Array do it "should be comparable" do ([8,9,10] > [1,2,3]).should be_true should end end Output: ....F 1) NoMethodError in 'Array should be comparable' undefined method `>' for [8, 9, 10]:Array ./spec/dice_spec.rb:43: Finished in 0.039464 seconds 5 examples, 1 failure INCLUDE COMPARABLE MODULE To solve the previous issue, just include the Comparable module in the dice.rb file. I'll put in a simplify form purposely to play with ruby possibilities :). class Array; include Comparable; end 28
  • 29. Chapter 2: Reproducing the War Game Dice Now the test pass. NUMBER OF DICE Now I'll work on the first requirement: The attack and defence should use 1, 2 or 3 dice. I'll put intentionally a number different of 1, 2, 3 to cause an error. describe Wardice do it "The attack and defence should use 1, 2 or 3 dice" do wardice = Wardice new(0, 3) Wardice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) end it "Should compare from bigger to less values and save in array result" end class Wardice attr_reader :red :yellow red, def initialize red, yellow) initialize( @red, @yellow = red, yellow end end Output: 'Wardice The attack and defence should use 1, 2 or 3 dice' FAILED expected "0" to match /^[1-3]$/ ./spec/dice_spec.rb / / rb:50: 29
  • 30. Learn BDD Playing Dice! - Your behavior is have fun Finished in 0.032203 seconds 8 examples, 1 failure, 2 pending SOLVING THE NUMBER ISSUE If the class was initialized with numbers differents of the range (1..3) then the variables will be filled with a rand number between the range. I'll make also a little refactory in the spec file to put a situation that a number of dice is correct. You can see below the solution. class WarDice attr_reader :red :yellow red, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? end end describe WarDice do it "The attack and defence should use 1, 2 or 3 dice" do wardice = Wardice new(0, 7) Wardice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) wardice2 = Wardice new(2, 3) Wardice.new wardice2.red should == 2 red.should wardice2.yellow should == 3 yellow.should end 30
  • 31. Chapter 2: Reproducing the War Game Dice it "Should compare from bigger to less values and save in array result" end DECREASE SORT ARRAY This is a important requirement, but I remembered only now: wardice Should provide yellow and red dice results with an array in decreasing sort. You can see the solution below: describe WarDice do it "The attack and defence should use 1, 2 or 3 dice" do wardice = WarDice new(0, 7) WarDice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) wardice2 = WarDice new(2, 3) WarDice.new wardice2.red should == 2 red.should wardice2.yellow should == 3 yellow.should end it "Should provide yellow and red dice results with an array in decreasing sort" do wardice = Wardice new(3, 3) Wardice.new wardice.reddice is_a?(Array).should be_true reddice.is_a? should wardice.yellowdice is_a?(Array).should be_true yellowdice.is_a? should wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice reddice.sort should reddice wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice yellowdice.sort should yellowdice end it "Should compare from bigger to less values and save in array result" end 31
  • 32. Learn BDD Playing Dice! - Your behavior is have fun class wardice attr_reader :red :yellow :reddice :yellowdice red, yellow, reddice, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @reddice = [] @yellowdice = [] @dice = Dice new Dice.new @red.times times{|row| @reddice[row] = [@dice.play } play] @yellow.times |row| @yellowdice[row] = [@dice.play } times{ play] end end Output: 'wardice Should provide yellow and red dice results with an array in decreasing sort' FAILED expected: [[5], [2], [4]], got: [[5], [4], [2]] (using == ==) ./spec/dice_spec.rb / / rb:63: Finished in 0.035218 seconds 9 examples, 1 failure, 2 pending 32
  • 33. Chapter 2: Reproducing the War Game Dice SOLVING SORTING ARRAY ISSUE class WarDice attr_reader :red :yellow :reddice :yellowdice red, yellow, reddice, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @reddice = [] @yellowdice = [] @dice = Dice new Dice.new @red.times times{|row| @reddice[row] = [@dice.play } play] @yellow.times |row| @yellowdice[row] = [@dice.play } times{ play] @reddice.sort! sort!{|x,y| y <=> x } @yellowdice.sort! sort!{|x,y| y <=> x } end end Now the test pass. COMPARING VALUES Let's work now in the last requirement: Should compare from bigger to less values and save in array result describe Wardice do it "The attack and defence should use 1, 2 or 3 dice" do 33
  • 34. Learn BDD Playing Dice! - Your behavior is have fun wardice = Wardice new(0, 7) Wardice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) wardice2 = Wardice new(2, 3) Wardice.new wardice2.red should == 2 red.should wardice2.yellow should == 3 yellow.should end it "Should provide yellow and red dice results with an array in decreasing sort" do wardice = Wardice new(3, 3) Wardice.new wardice.reddice is_a?(Array).should be_true reddice.is_a? should wardice.yellowdice is_a?(Array).should be_true yellowdice.is_a? should wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice reddice.sort should reddice wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice yellowdice.sort should yellowdice end it "Should compare from bigger to less values and save in array result" do wardice = Wardice new(3, 2) Wardice.new wardice.reddice first.should > wardice.reddice last reddice.first should reddice.last wardice.attack attack wardice.result result[0].should == "Red Win" if wardice.reddice should reddice[0] > wardice.yellowdice yellowdice[0] wardice.result result[0].should == "Yellow Win" if wardice.reddice should reddice[0] <= wardice.yellowdice yellowdice[0] end end The final WarDice class: class Wardice attr_reader :red :yellow :reddice :yellowdice :result red, yellow, reddice, yellowdice, 34
  • 35. Chapter 2: Reproducing the War Game Dice def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @reddice = [] @yellowdice = [] @result = [] @dice = Dice new Dice.new @red.times times{|row| @reddice[row] = [@dice.play } play] @yellow.times |row| @yellowdice[row] = [@dice.play } times{ play] @reddice.sort! sort!{|x, y| y <=> x } @yellowdice.sort! sort!{|x, y| y <=> x } end def attack @reddice.each_with_index do |item, index| each_with_index next if @yellowdice[index].nil? nil? reddice = item yellowdice = @yellowdice[index] if reddice > yellowdice @result << "Red Win" else @result << "Yellow Win" end end end end 35
  • 36. Learn BDD Playing Dice! - Your behavior is have fun PLAY WITH THE WARDICE CLASS Open irb and write the next sequence: >> require 'dice' => true Initialize the WarDice class. The first parameter is the number of red dice and the second is the number of yellow dice: >> wardice = WarDice new(2, 3) WarDice.new => #<WarDice:0xb7b0b410 @yellowdice=[[6], [1], [1]], @reddice=[[3], [1]], @dice=#<Dice:0xb7b0ae0c @number=6>, yellow3, result["Yellow Win", "Yellow Win"], red2 = > Show numbers in yellow and red dice: >> puts wardice.reddice reddice 3 1 => nil >> puts wardice.yellowdice yellowdice 6 1 1 => nil Show result: >> puts wardice.result result Yellow Win Yellow Win => nil 36
  • 37. Chapter 2: Reproducing the War Game Dice All output in one command: >> war.reddice each_with_index{ |item, index| puts "Red:#{item} Yellow:#{war.yellowdice reddice.each_with_index yellowdice[index]} - #{war.result result[index]}"} Red:3 Yellow:6 - Yellow Win Red:1 Yellow:1 - Yellow Win => [[3], [1]] Now we have the tools to play. Then the next chapter we'll use this classes to make a nice graphic application using Shoes. 37
  • 38. Learn BDD Playing Dice! - Your behavior is have fun Chapter 3 Playing dice with shoes A LITTLE TEST WITH DICE CLASS AND SHOES Now let's create a graphic interface using Shoes that will use the class WarDice. But first let's' make a simple test with the class Dice. You have to create a new file diceshoes.rb, then paste the code below inside it and save the file at the same directory of dice.rb file. Finally, execute it with shoes to see the result. Observe that I just included the dice.rb file with a require in the beginning of the code below: require 'dice' Shoes app :title => "Test with dice class", :width => 500, :height => 500 do Shoes.app background aliceblue para "Welcome! This is an example using Dice class.", :weight => "bold" dice = Dice new Dice.new 38
  • 39. Chapter 3: Playing dice with shoes # Print dice numbers with random colors 1_000.times do times r, g, b = rand, rand, rand para dice.play :stroke => rgb **3, g** play, rgb(r** **3, b** **3), :size => "large" end end Output: THE WAR DICE SHOES CODE Finally the last application. Copy the following code in a new file and save with the name wardiceshoes.rb in the lib folder. I put some remarks across the code to facilitate the understanding. Have a nice experiment. 39
  • 40. Learn BDD Playing Dice! - Your behavior is have fun require 'dice' Shoes app :title => "Dice of War game", :width => 500, :height => 500 do Shoes.app background gradient black, teal ) gradient( # List with number of red dice: 1, 2 or 3 para "Red", :stroke => tomato @numberreddice = list_box :items => ["1", "2", "3"], :width => 70, :choose => "3" do |list| end para " X ", :stroke => snow # List with number of yellow dice: 1, 2 or 3 @numberyellowdice = list_box :items => ["1", "2", "3"], :width => 70, :choose => "3" do |list| end para "Yellow", :stroke => yellow # Define an aleatory position @a = @b = @c = [] (40..200).step step(10){ |x| @a << x } (230..450).step step(10){ |y| @b << y } (80..450).step step(10){ |z| @c << z } | # Variables that will store values of wardice object @reddice = @yellowdice = @resulttext = [] button "Attack", :width => 80 do # Clear the screen @dice.each |d| d.remove } each{ remove @resulttext.each |a| a.remove } each{ remove 40
  • 41. Chapter 3: Playing dice with shoes # The wardice object is initializing wardice = WarDice new( @numberreddice.text to_i, @numberyellowdice.text to_i ) WarDice.new text.to_i text.to_i @reddice = wardice.reddice reddice @yellowdice = wardice.yellowdice yellowdice @result = wardice.result result # Every dice is drawn in random position @reddice.each |item| draw @a[rand each{ draw( rand(@a.length length)], @c[rand rand(@c.length length)], item.to_s to_i, 1, true ) } to_s.to_i @yellowdice.each |item| draw @b[rand each{ draw( rand(@b.length length)], @c[rand rand(@c.length length)], item.to_s to_i, 2, true )} to_s.to_i end button "Verify", :width => 80 do # Clear the screen @dice.each |d| d.remove } each{ remove @resulttext.each |a| a.remove } each{ remove # Initial position of dice leftyellow = 250 leftred = 150 topred = topyellow = 100 # Every dice are drawn in a defined position @reddice.each do |item| each draw leftred, topred, item.to_s to_i, 1, false ) draw( to_s.to_i topred += 100 end @yellowdice.each do |item| each draw leftyellow, topyellow, item.to_s to_i, 2, false ) draw( to_s.to_i topyellow += 100 end 41
  • 42. Learn BDD Playing Dice! - Your behavior is have fun # Initial position of result leftresult = 300 topresult = 80 # The results are drawn in defined positions @result.each_with_index do |item, index| each_with_index @resulttext[index] = para item.to_s :stroke => snow, :top => topresult, :left => leftresult to_s, topresult += 100 end end # Method draw was based in the Pretty Dice project written by Ed Heil @dice = [] def draw left, top, number, color, rotate ) draw( imagewidth = 60 imageheight = 60 i = image imagewidth, imageheight, image( :top => top - imagewidth / 2, :left => left - imagewidth / 2, :shadow => 10, :center => true ) do if color == 1 strokecolor = red fillrectanglecolor = tomato filldotscolor = darkred else strokecolor = yellow fillrectanglecolor = lightgoldenrodyellow 42
  • 43. Chapter 3: Playing dice with shoes filldotscolor = chocolate end sw = 1 strokewidth sw stroke strokecolor fill fillrectanglecolor inset = 2 inset2 = 8 rect inset, inset, imagewidth-inset-sw, imageheight-inset-sw, 10 ) rect( - - - - fill filldotscolor ovalradius = 10 low = inset2 high = imagewidth - inset2 - ovalradius mid = ( imagewidth - ovalradius ) / 2 oval mid, mid, ovalradius ) if number % 2 == 1 oval( if number > 1 oval low, low, ovalradius ) oval( oval high, high, ovalradius ) oval( end if number > 3 oval low, high, ovalradius ) oval( oval high, low, ovalradius ) oval( end if number > 5 43
  • 44. Learn BDD Playing Dice! - Your behavior is have fun oval mid, low, ovalradius ) oval( oval mid, high, ovalradius ) oval( end end # end of image block i.rotate rand 359 ) ) if rotate rotate( rand( @dice << i end end PLAYING WITH WAR DICE SHOES APP Below you can see the War Dice app in action. You must choose the number of red and yellow dice in respective list box. Then click in Attack button to play dice. Now just have fun! 44
  • 45. Chapter 3: Playing dice with shoes Now click in verify button to know who wins! 45
  • 46. Learn BDD Playing Dice! - Your behavior is have fun 46