<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-21814360</id><updated>2009-02-20T23:45:47.179-08:00</updated><title type='text'>Anthony's Software Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-21814360.post-114441803561788104</id><published>2006-04-07T09:05:00.000-07:00</published><updated>2007-08-03T17:10:08.653-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>TDDing a Card Game part 6</title><content type='html'>&lt;div&gt;
&lt;a href='http://anthonysseblog.blogspot.com/2006/03/tdding-card-game-part-5.html'&gt;Last time&lt;/a&gt; we dealt with how Player notifies game that it's stuck. I also expressed some concern that I haven't extracted the game class. This time we'll start with one more test for player then we'll look at extracting the game class from SpitPlayerRules. Along the way we'll see  the &lt;a href='http://www.objectmentor.com/resources/articles/srp'&gt;Single Responsibility Principle&lt;/a&gt;.
&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;One Last Player Tweak For Now&lt;/h2&gt;
&lt;p&gt;
In the game of Spit there are two piles on which the players spit. Adding the second pile is the last little tweak I want to make to Player before I extract a game. I'll write a test to force the Player to spit on a second pile. 
&lt;pre&gt;class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @pile_one = SpitPile.new(7)
    @stock = []
    @spit_reserve = []
  end
&lt;span style="font-weight:bold;"&gt;
  def test_player_can_play_on_either_pile
    @pile_two = SpitPile.new(5)
    @player.hand = [ 2, 3, 2, 3, 4 ]
    @player.play
    assert_equal [7] , @pile_one.to_a
    assert_equal [5, 4, 3, 2, 3, 2], @pile_two.to_a
  end&lt;/span&gt;
&lt;/pre&gt;
Notice that no card in @player.hand can be played on @pile_one. That will force the player to spit on @pile_two. We should run the test to make sure it fails... It does. Looking at the current Player code it's pretty clear that we need to change the bold line below
&lt;pre&gt;class Player
  def spit
    card_to_play = @hand.pop 
    &lt;span style="font-weight:bold;"&gt;unless @game.spit_on_one(card_to_play)&lt;/span&gt;
      @invalid_moves += 1
      @hand.unshift(card_to_play)
    end
    if @invalid_moves == 5
      @game.stuck
      @invalid_moves = 0
    end
  end
end&lt;/pre&gt;
to this 
&lt;pre&gt;unless @game.spit_on_one(card_to_play) or @game.spit_on_two(card_to_play)&lt;/pre&gt;
Of course we're assuming that @game responds to #spit_on_two. Let's make it so. Remember that @game is still just an instance of SpitPlayerRules
&lt;pre&gt;class SpitPlayerRules &lt; Test::Unit::TestCase
  # game methods
  def spit_on_two( card )
    @pile_two.play card
  end
end&lt;/pre&gt;
Now we'll run the tests and move on...
&lt;/p&gt;
&lt;p&gt;
D'oh. We have two failing tests: #test_player_draws_when_hand_is_short and #test_when_stuck_player_asks_for_new_spit. Can you spot why? Hmm, maybe the error message will help. It's the same for both failures.
&lt;pre&gt;NoMethodError: undefined method `play' for nil:NilClass
    SpitTest.rb:70:in `spit_on_two'
    ./spit.rb:48:in `spit'
    ./spit.rb:38:in `play'
    SpitTest.rb:48:in `test_player_draws_when_hand_is_short'&lt;/pre&gt;
Ah ha! Player is trying to #spit_on_two, but @pile_two is nil in all but the test we just wrote. So I'll add it to the setup and initialize it with something that isn't playable.
&lt;pre&gt;class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @pile_one = SpitPile.new(7)
    &lt;span style="font-weight:bold;"&gt;@pile_two = SpitPile.new(0)&lt;/span&gt;
    @stock = []
    @spit_reserve = []
  end
end&lt;/pre&gt;
We're on a green bar so let's refactor. I notice that the logic in Player#spit is rather crufty and obtuse. Let's see if you agree.
&lt;pre&gt;class Player
  def spit
    card_to_play = @hand.pop 
    unless @game.spit_on_one(card_to_play) or @game.spit_on_two(card_to_play)
      @invalid_moves += 1
      @hand.unshift(card_to_play)
    end
    if @invalid_moves == 5
      @game.stuck
      @invalid_moves = 0
    end
  end
end&lt;/pre&gt;
It looks like in this method Player spits a card then assess the situation. The Single Responsibility Principle (SRP) says that a class should have one and only one reason to change. I like to extend this down to the method level as well. In this case I think we should split this method in two. First I'll extract each conditional into it's own method. The tests still pass. Player#spit isn't pulling it's own weight, so I'm going to inline it. Test are still passing. I'll reorder the statements in the while loop of Player#play and then I'll show the code. Okay, the tests are passing and here's the code.
&lt;pre&gt;class Player
  def play
    while(!@hand.empty?)
      assess_situation
      draw
      spit_card
    end
  end
  def spit_card 
    card_to_play = @hand.pop 
    unless @game.spit_on_one(card_to_play) or @game.spit_on_two(card_to_play)
      @invalid_moves += 1
      @hand.unshift(card_to_play)
    end
  end
  def assess_situation
    if @invalid_moves == 5
      @game.stuck
      @invalid_moves = 0
    end
  end
end&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;a id='smashing_with_srp'&gt;&lt;/a&gt;
&lt;h2&gt;Smashing SpitPlayerRules with SRP&lt;/h2&gt;
&lt;p&gt;
Speaking of SRP, we have a big issue with SRP in the SpitPlayerRules class. Right now SpitPlayerRules is both the test fixture and the game double. This is a clear violation of the principle. We've been aware of it for some time now. In fact it was a conscious decision to leave it alone, until now. We're going to extract the Game class from SpitPlayerRules. We're going to do this in very small steps and always keep the tests green because that's what the TDD people say to do. First I'll show the entire SpitPlayerRules, then I'll discuss each step and show the affected portions of the code.
&lt;/p&gt;
&lt;pre&gt;class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @pile_one = SpitPile.new(7)
    @pile_two = SpitPile.new(0)
    @stock = []
    @spit_reserve = []
  end
  def test_run_without_draw
    @player.hand = [ 2, 3, 4, 5, 6 ]
    @player.play
    assert_equal [7, 6, 5, 4, 3, 2] , @pile_one.to_a
  end
  def test_player_draws_when_hand_is_short
    @stock &lt;&lt; 2
    @player.hand = [3, 4, 5, 6]
    @player.play
    assert @stock.empty?, "player did not draw as expected"
  end
  def test_when_stuck_player_asks_for_new_spit
    @spit_reserve  &lt;&lt; 3 &lt;&lt; 6
    @player.hand = [2, 2, 3, 4, 5]
    @player.play
    assert @spit_reserve.empty?, "player did not ask for a new spit"
  end
  def test_player_can_play_on_either_pile
    @pile_two = SpitPile.new(5)
    @player.hand = [ 2, 3, 2, 3, 4 ]
    @player.play
    assert_equal [7] , @pile_one.to_a
    assert_equal [5, 4, 3, 2, 3, 2], @pile_two.to_a
  end

  # game methods
  def spit_on_one( card )
    @pile_one.play card
  end
  def spit_on_two( card )
    @pile_two.play card
  end
  def draw
    @stock.pop
  end
  def draw?
    ! @stock.empty?
  end 
  def stuck
    @pile_one.new_spit(@spit_reserve.pop)
  end 
end&lt;/pre&gt;
&lt;p&gt;
First we need an empty class to move all the game methods to.
&lt;pre&gt;class Game
end&lt;/pre&gt;
That was easy enough. And the tests are still green. Where do we go from here? Let's pick a method and move it to the new class. Remember we can't let the tests break so we'll need to give SpitPlayerRules an instance of Game to use. Sometimes it's easier to move methods and data in clumps. Let's move #draw, #draw?, and @stock. 
&lt;pre&gt;class Game
&lt;span style="font-weight:bold;"&gt;  attr_accessor :stock
  def draw
    @stock.pop
  end
  def draw?
    ! @stock.empty?
  end&lt;/span&gt;
end
class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
&lt;span style="font-weight:bold;"&gt;    @game = Game.new
    @game.stock = []&lt;/span&gt;
    @pile_one = SpitPile.new(7)
    @pile_two = SpitPile.new(0)
    @spit_reserve = []
  end
  def test_player_draws_when_hand_is_short
 &lt;span style="font-weight:bold;"&gt;   @game.stock &lt;&lt; 2&lt;/span&gt;
    @player.hand = [3, 4, 5, 6]
    @player.play
 &lt;span style="font-weight:bold;"&gt;   assert @game.stock.empty?, "player did not draw as expected"&lt;/span&gt;
  end
  # game methods
&lt;span style="font-weight:bold;"&gt;  def draw
    @game.draw
  end
  def draw?
    @game.draw?
  end &lt;/span&gt;
end&lt;/pre&gt;
Yes! The tests are still green. Alright all that's left is #stuck, #spit_on_*, @pile_*, and @spit_reserve. Let's move them.
&lt;pre&gt;class Game
  attr_reader :stock
  &lt;span style="font-weight:bold;"&gt;attr_reader :spit_reserve
  attr_accessor :pile_one
  attr_accessor :pile_two
  def spit_on_one( card )
    @pile_one.play card
  end
  def spit_on_two( card )
    @pile_two.play card
  end
  def stuck
    @pile_one.new_spit(@spit_reserve.pop)
  end &lt;/span&gt;
end
class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @game = Game.new
    @game.stock = []
    &lt;span style="font-weight:bold;"&gt;@game.pile_one = SpitPile.new(7)
    @game.pile_two = SpitPile.new(0)
    @game.spit_reserve = []&lt;/span&gt;
  end
  def test_run_without_draw
    @player.hand = [ 2, 3, 4, 5, 6 ]
    @player.play
&lt;span style="font-weight:bold;"&gt;    assert_equal [7, 6, 5, 4, 3, 2] , @game.pile_one.to_a&lt;/span&gt;
  end
  def test_when_stuck_player_asks_for_new_spit
    &lt;span style="font-weight:bold;"&gt;@game.spit_reserve  [3, 6]&lt;/span&gt;
    @player.hand = [2, 2, 3, 4, 5]
    @player.play
    &lt;span style="font-weight:bold;"&gt;assert @game.spit_reserve.empty?, "player did not ask for a new spit"&lt;/span&gt;
  end
  def test_player_can_play_on_either_pile
    @game.pile_two = SpitPile.new(5)
    @player.hand = [ 2, 3, 2, 3, 4 ]
    @player.play
&lt;span style="font-weight:bold;"&gt;    assert_equal [7] , @game.pile_one.to_a
    assert_equal [5, 4, 3, 2, 3, 2], @game.pile_two.to_a&lt;/span&gt;
  end
  # game methods
  def spit_on_one( card )
    &lt;span style="font-weight:bold;"&gt;@game.pile_one.play card&lt;/span&gt;
  end
  def spit_on_two( card )
    &lt;span style="font-weight:bold;"&gt;@game.pile_two.play card&lt;/span&gt;
  end
  def stuck
    &lt;span style="font-weight:bold;"&gt;@game.pile_one.new_spit(@spit_reserve.pop)&lt;/span&gt;
  end 
end&lt;/pre&gt;
Green Bar! Now let's move the game setup from SpitPlayerRules#setup to Game#initialize.
&lt;pre&gt;class Game
  def initialize
    @stock = []
    @spit_reserve = []
    @pile_one = SpitPile.new(7)
    @pile_two = SpitPile.new(0)
  end
end&lt;/pre&gt;
Finally, we can replace the self shunt of SpitPlayerRules with @game, and remove all the game specific methods from SpitPlayerRules.
&lt;pre&gt;class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @game = Game.new
    @player = Player.new(@game)
  end
end&lt;/pre&gt;
The tests are still green. One last thing, Game#initialize is setting up for the tests, and all of the data members of Game have accessors. Maybe we should introduce a GameDouble that will setup the state and provide access to the members. It might look like this
&lt;pre&gt;class GameDouble &lt; Game
  attr_reader :stock
  attr_reader :spit_reserve
  attr_accessor :pile_one
  attr_accessor :pile_two
  def initialize
    @stock = []
    @spit_reserve = []
    @pile_one = SpitPile.new(7)
    @pile_two = SpitPile.new(0)
  end
end&lt;/pre&gt;
I rather like that, so I'll hook it into the Player rules and clean up Game accordingly.
&lt;pre&gt;class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @game = GameDouble.new
    @player = Player.new(@game)
  end
end&lt;/pre&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;Until Next Time&lt;/h2&gt;
&lt;p&gt;Whew. That was as lot of code movement. I'll show the code in it's entirety below.  Let's look at what we've done today. We've finally broken out a Game class, we introduced a test double for that game class, and we brought the Player class one step closer to done. There are a few warts. The most notable wart is the integers that represent cards. We need to do something about that next time.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114441803561788104?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114441803561788104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114441803561788104' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114441803561788104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114441803561788104'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/04/tdding-card-game-part-6.html' title='TDDing a Card Game part 6'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-114425504795484719</id><published>2006-04-05T09:26:00.000-07:00</published><updated>2006-04-05T09:37:27.976-07:00</updated><title type='text'>Forming Riverside.rb</title><content type='html'>If you're in the Riverside, California area and are into Ruby or are looking into Ruby, then you might be interested in starting the Riverside Ruby Users Group. If you're interested join &lt;a href="https://www.cs.ucr.edu/mailman/listinfo/rug"&gt;the mailing list&lt;/a&gt;, and introduce yourself. We'll work out the when and where once we've got the who.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114425504795484719?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114425504795484719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114425504795484719' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114425504795484719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114425504795484719'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/04/forming-riversiderb.html' title='Forming Riverside.rb'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-114347176624901792</id><published>2006-03-27T06:42:00.000-08:00</published><updated>2006-03-27T07:02:46.260-08:00</updated><title type='text'>SD Ruby User Group</title><content type='html'>&lt;a href="http://glu.ttono.us"&gt;Kevin Clark&lt;/a&gt; and many others are &lt;a href="http://glu.ttono.us/articles/2006/03/25/san-diego-ruby-users-group-revival"&gt;reviving the San Diego Ruby Users Group&lt;/a&gt;. I am very excited, and I plan to help out in any way I can. I won't be able to make many of the meetings though. The reason I won't is I live almost 90 miles from San Diego even though I work there. I wonder if there'd be enough interest in a Riverside/San Bernardino RUG?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114347176624901792?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114347176624901792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114347176624901792' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114347176624901792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114347176624901792'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/03/sd-ruby-user-group.html' title='SD Ruby User Group'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-114200750308556423</id><published>2006-03-27T06:20:00.000-08:00</published><updated>2006-03-27T08:05:37.353-08:00</updated><title type='text'>TDDing a Card Game part  5</title><content type='html'>&lt;div&gt;
&lt;p&gt;In &lt;a href="http://anthonysseblog.blogspot.com/2006/02/tdding-card-game-part-3.html"&gt;part three&lt;/a&gt; We started with four questions. 
&lt;ul&gt;
&lt;li&gt;What happens when player makes an invalid move?&lt;/li&gt;
&lt;li&gt;How does Player draw from its stock pile?&lt;/li&gt;
&lt;li&gt;How does Player get notified of the end of game play?&lt;/li&gt;
&lt;li&gt;Does player notify Game when its out of cards?&lt;/li&gt;
&lt;/ul&gt;
We developed how Player draws a card in that entry. One thing that has been bugging me is that we don't have an actual Game class yet. We do have most of an interface or protocol that the Game class will implement, but it is completely contained in the SpitPlayerRules TestCase. Should I extract it now? Should I have stubbed a Game class out earlier instead of using the test case as a double? Should I wait a little longer before extracting it? I think I'll wait for now because I want the interface between Player and Game to emerge a little bit more. Of course this might not be the best idea.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;Bad Move&lt;/h2&gt;
&lt;p&gt;What happens when player makes an invalid move? An invalid move could be trying to draw a card when the Player already has five cards in its hand or trying to play a card out of sequence. Thinking ahead a bit and looking at the &lt;a href="http://anthonysseblog.blogspot.com/2006/03/tdding-card-game-why-and-what.html"&gt;last entry&lt;/a&gt;, we know at some point we want to let third parties write Players, so I don't think we want Player to be responsible for enforcing the five card in the hand limit. The other invalid move is part of the interface between player and game, and is addressed by the &lt;a href="http://en.wikipedia.org/wiki/Spit_(card_game)"&gt;rules of the game&lt;/a&gt;. Specifically, the Players will turn a new spit card when both Player's are stuck. We are, for the moment, dealing with one player, so we will focus on how a Player notifies the Game that it's stuck.  Let's express that in Ruby
&lt;pre&gt;
class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @pile_one = [7]
    @pile_two = [7]
    @stock = []
  end
  def test_when_stuck_player_asks_for_new_spit
    @spit_reserve = [6]
    @player.hand = [2, 2, 3, 4, 5]
    @player.play
    assert @spit_reserve.empty?, "player did not ask for a new spit"
  end
end
&lt;/pre&gt;
&lt;/p&gt;
&lt;h2&gt;To Prefactor or Not To Prefactor&lt;/h2&gt;
&lt;p&gt;
I expect that Game needs to notify Player when a move is invalid, and that will introduce duplication in the game double because it must implement the logic that is in SpitPile. There are at least two options here. One, we could press on and let the actual duplication show us what we need. Two, we could back out the failing test and replace the array, @pile_one, with a SpitPile. In this case I'm going with option two because I think the need for SpitPile is clear. Under other circumstances I might choose differently.
&lt;/p&gt;
&lt;p&gt;
Looking over the current code I noticed that @pile_two is unused, so I'll remove it. Moving on to the replacement. We need to change the initialization of @pile_one in the setup and the #&lt;&lt; in spit_on_one. I'll show that and run the tests.
&lt;pre&gt;
class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
&lt;span style="font-weight:bold;"&gt;    @pile_one = SpitPile.new(7)&lt;/span&gt;
    @stock = []
  end
  # game methods
  def spit_on_one( card )
&lt;span style="font-weight:bold;"&gt;    @pile_one &lt;&lt; card&lt;/span&gt;
  end
  def draw
    @stock.pop
  end
  def draw?
    ! @stock.empty?
  end 
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;
D'oh! The #test_run_without_draw fails. The message points to the following
&lt;pre&gt;
class SpitPlayerRules &lt; Test::Unit::TestCase
  def test_run_without_draw
    @player.hand = [ 2, 3, 4, 5, 6 ]
    @player.play
&lt;span style="font-weight:bold;"&gt;    assert_equal [7, 6, 5, 4, 3, 2] , &lt;span style="font-style:strike;"&gt;@pile_one&lt;/span&gt;&lt;/span&gt;
  end
&lt;/pre&gt;
Obviously SpitPile is not an Array, so that comparison won't work. I'll just add a test for a SpitPile#to_a method, and then implement and use it.
&lt;pre&gt;
class SpitPileRules &lt; Test::Unit::TestCase
  def setup
    @pile = SpitPile.new( 2 )
  end
  def test_to_a
    assert @pile.play(3)
    assert_equal [2, 3], @pile.to_a
  end
end
class SpitPile
  def initialize( first_card )
    @pile = [ first_card ]
  end
  def to_a
    @pile
  end 
end
class SpitPlayerRules &lt; Test::Unit::TestCase
  def test_run_without_draw
    @player.hand = [ 2, 3, 4, 5, 6 ]
    @player.play
&lt;span style="font-weight:bold;"&gt;    assert_equal [7, 6, 5, 4, 3, 2] , &lt;span style="font-style:strike;"&gt;@pile_one.to_a&lt;/span&gt;&lt;/span&gt;
  end
&lt;/pre&gt;
&lt;/p&gt;
&lt;h2&gt;Passing the Test&lt;/h2&gt;
&lt;p&gt;
Okay, let's restore the test for an invalid move and a stuck player and see if we can make it pass. 
&lt;pre&gt;
class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @pile_one = SpitPile.new(7)
    @stock = []
    @spit_reserve = []
  end
  def test_when_stuck_player_asks_for_new_spit
    @spit_reserve = [6]
    @player.hand = [2, 2, 3, 4, 5]
    @player.play
    assert @spit_reserve.empty?, "player did not ask for a new spit"
  end
end
&lt;/pre&gt;
I had a little trouble making that pass. Mostly because when I first wrote the test I wrote &lt;pre&gt;@spit_reserve = [6]&lt;/pre&gt; That didn't provide the Player with enough valid moves. Changing it to &lt;pre&gt;@spit_reserve = [3, 6]&lt;/pre&gt; solved that problem. Let's review the code that makes the test pass. It's in Player#spit, which is called from Player#play&lt;pre&gt;
class Player
  attr_accessor :hand
  def initialize( game )
    @game = game
  end
  def spit
    card_to_play = @hand.pop 
    unless @game.spit_on_one(card_to_play) 
      @invalid_moves += 1
      @hand.unshift(card_to_play)
    end
    if @invalid_moves == 5
      @game.stuck
      @invalid_moves = 0
    end   
  end
end
&lt;/pre&gt;
As you may notice the logic here is crufty. I think that it's okay for now because we are using this Player to explore the interaction between game and Player. I fully expect to make a few other Player class for AI and human play. This simple Player is essentially just playing cards in the order they are in @hand and counting how many @invalid_moves he gets. Then he tells the game when he's stuck. This required that I add the following to the game double and SpitPile.
&lt;pre&gt;
class SpitPlayerRules &lt; Test::Unit::TestCase
  # game methods
  def stuck
    @pile_one.new_spit(@spit_reserve.pop)
  end 
end
class SpitPile
  def new_spit( card )
    @pile &lt;&lt; card
  end
end
&lt;/pre&gt;
And now the tests are all passing. 
&lt;/p&gt;
&lt;h2&gt;Stopping For Today&lt;/h2&gt;
&lt;p&gt;
I'm still concerned about not having a game class, but I can see its shape a little more clearly now. I think one more tweak to the Player class and then I'll extract the game. I'm out of time for now, so that'll have to wait for the next entry. I might even get ambitious and get a new entry up before next week. Until then.&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114200750308556423?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114200750308556423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114200750308556423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114200750308556423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114200750308556423'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/03/tdding-card-game-part-5.html' title='TDDing a Card Game part  5'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-114125137257822628</id><published>2006-03-04T23:45:00.000-08:00</published><updated>2006-03-06T07:28:43.396-08:00</updated><title type='text'>TDDing a Card Game - The Why and What</title><content type='html'>&lt;div&gt;
I've noticed, while reading the previous three entries, I haven't made very clear my plan. I've described the game, and jumped right into the code. I haven't given a clear direction for this project. Also, I haven't explained why I'm writing this. So I'm going to spend this post explaining the Why and the What of this series. 
&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;First, the Why&lt;/h2&gt;
I was first introduced to TDD over two years ago. Since that time I have regularly tried to apply it in the work that I do, but often the code base and time constraints conspire against my efforts to work in a completely test driven fashion. While I am often impressed by the simplicity TDD helps me create, I regularly find myself stuck against something I don't know how to test. In the face of looming deadlines I often buckle and just code up a mess that kind of works for now.
&lt;br/&gt;
Chad Fowler's &lt;a href="http://www.pragmaticprogrammer.com/titles/mjwti/index.html"&gt;book on architecting your career&lt;/a&gt; is &lt;a href="http://anthonysseblog.blogspot.com/2006/02/why-im-starting-to-blog.html
"&gt;the reason I started this blog&lt;/a&gt;. As result of that first exercise from the book, I realized that publishing could provide a good way of reflecting on why and how I do the things I do. This reflection will be a crucial part of improving my skills and abilities. I decided I needed a project to practice in a completely test driven way.
&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;Now, the What&lt;/h2&gt;
In the &lt;a href="http://anthonysseblog.blogspot.com/2006/02/tdding-card-game-part-1.html"&gt;first post&lt;/a&gt; in this series I described the card game Spit. I then jumped right into implementing it. I kind of had in my head where I was planning to go, but it is not as clear as it could be. Since my time to devote to writing this is limited, and I am  often absent minded, I need to write down a high level path that will help me resume when I need too.
&lt;br /&gt; 
The first three entries in this series are headed towards a player versus AI on the command line type game. One of the primary goals for me in writing this program is to stretch my ability in places where I think TDD will be hard. With that in mind, I want a full GUI player versus AI mode to help explore the difficulties I imagine for test driving GUIs. A player API to allow custom AI players would be neat. Player versus player mode would expose some of the  perceived difficulty in testing network interactions. A web application for player versus player mode right in a browser would allow me to explore Ruby on Rails. 
&lt;br/&gt;
Whew! Did I leave out anything? I know all that is extremely ambitious. In fact, it seems a lot like that first meeting with a customer when they have a great new idea. Well good. Sometimes I think I will put a customer hat on and review the work I've done and strategize about the next steps. For now I'll put the hat away and in the next entry I'll work towards the command line version of the game.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114125137257822628?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114125137257822628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114125137257822628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114125137257822628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114125137257822628'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/03/tdding-card-game-why-and-what.html' title='TDDing a Card Game - The Why and What'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-114063814716924714</id><published>2006-02-22T10:32:00.000-08:00</published><updated>2006-02-23T08:39:53.100-08:00</updated><title type='text'>TDDing a Card Game part 3</title><content type='html'>&lt;div&gt;
Last week I ended with the following questions
&lt;ul&gt;
&lt;li&gt;What happens when player makes an invalid move?&lt;/li&gt;
&lt;li&gt;How does Player draw from its stock pile?&lt;/li&gt;
&lt;li&gt;How does Player get notified of the end of game play?&lt;/li&gt;
&lt;li&gt;Does player notify Game when its out of cards?&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Today I'll pick start by picking a question and translating it into a test. I'll focus on the stock pile question. 
&lt;pre&gt;
#SpitPlayerRules
def test_player_draws_when_hand_is_short
  @stock = [2]
  player = Player.new(self)
  player.hand = [3, 4, 5, 6]
  @pile_one = [7]
  @pile_two = [7]
  player.play
  assert @stock.empty?, "player did not draw as expected"
end
&lt;/pre&gt;
Remember that SpitPlayerRules is using the &lt;a href="http://tap.testautomationpatterns.com:8080/Self%20Shunt.html"&gt;self shunt pattern&lt;/a&gt; so it is a double (think stunt double) for the still theoretical Game object. I've primed the Player under test with a hand that is one card short. Also I've assumed that somehow that Player will be able to draw from the @stock that the test/Game double has. In our implementation we need to consider how the Game communicates to the Player that the stock pile is empty. I ran that and it failed predictably.
&lt;/div&gt;
&lt;div&gt;
Here is the old Player#play
&lt;pre&gt;
def play
  while(!@hand.empty?)
    @game.spit_on_one(@hand.pop)
  end
end
&lt;/pre&gt;
Should we draw before or after we spit? For now I'll say before, and implement the draw as quickly as I can 
&lt;pre&gt;
def play
  while(!@hand.empty?)
    if @hand.size &lt; 5 and @game.draw?
      @hand &lt;&lt; @game.draw 
    end
    @game.spit_on_one(@hand.pop)
  end
end
&lt;/pre&gt;
Before this can run we need to implement the two methods draw and draw? on our Game double.
&lt;pre&gt;
#SpitPlayerRules
def draw
  @stock.pop
end
def draw?
  ! @stock.empty?
end
&lt;/pre&gt;
I'll just run the test and ... D'oh I need to make @stock an empty array in #test_run_without_draw to make it pass. Good that was fairly easy. Now on to the text test.
&lt;/div&gt;
&lt;div&gt;
Wait! The TDD mantra is red (check), green (check), REFACTOR. Okay is there anything we can do to make the code simpler? What is Simple Code? There are several formulations of guidelines for simplicity in code &lt;a href="http://xp.c2.com/XpSimplicityRules.html"&gt;here&lt;/a&gt;. The first guideline is "runs all tests", and we are good there. The next is "contains no duplication". While the Player class is acceptable. Its tests are not. The duplication is the set up the of the Player under test and the Game double's state. I'll factor that out into setup method.
&lt;pre&gt;
#SpitPlayerRules 
def setup 
  @player = Player.new(self)
  #Game double's state
  @pile_one = [7]
  @pile_two = [7]
  @stock = []
end
def test_run_without_draw
  @player.hand = [ 2, 3, 4, 5, 6 ]
  @player.play
  assert_equal [7, 6, 5, 4, 3, 2] , @pile_one
end
def test_player_draws_when_hand_is_short
  @stock &lt;&lt; 2
  @player.hand = [3, 4, 5, 6]
  @player.play
  assert @stock.empty?, "player did not draw as expected"
end
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
The third guideline is "expresses all the ideas you want to express". Looking at Player#play I think there are two ideas that are contained in that one method: draw and spit. I'll extract a method for each concept.
&lt;pre&gt;
#Player
def play
  while(!@hand.empty?)
    draw
    spit
  end
end
def draw
  if @hand.size &lt; 5 and @game.draw?
    @hand &lt;&lt; @game.draw 
  end    
end
def spit
  @game.spit_on_one(@hand.pop)    
end
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
The final guideline "minimizes classes and methods". It makes me think twice about the decision to extract #spit. I'm a little uncertain if the #spit method is pulling its weight. On the one hand it is only one line long. On the other hand it makes explicit the action in the card game and provides a place for any more advanced decision making at that point in the game. I think I'll keep it for now.
&lt;/div&gt;
&lt;div&gt;
I'm going to stop here because I'm trying to spend only an hour on this entry. I think we've made some progress here. The interaction between Player and Game is starting to show up in the SpitPlayerRules class. We covered some guidelines for simple code and applied them. And we answered one of the questions we asked last week. So until next time I'll leave you with a listing of the current state of things.
&lt;/div&gt;
&lt;div&gt;
&lt;pre&gt;
#--------------Spit.rb
class SpitPile
  def initialize( first_card )
    @pile = [ first_card ]
  end
  def play( card )
    if in_sequence?(card)
      @pile &lt;&lt; card
      return true
    end
    false
  end
  def to_s 
    @pile.join(', ')
  end
  def top_card
    @pile.last
  end
  def in_sequence?( card )
    (card - top_card).abs == 1
  end
end

class Player
  attr_accessor :hand
  def initialize( game )
    @game = game
  end
  def play
    while(!@hand.empty?)
      draw
      spit
    end
  end
  def draw
    if @hand.size &lt; 5 and @game.draw?
      @hand &lt;&lt; @game.draw 
    end    
  end
  def spit
    @game.spit_on_one(@hand.pop)    
  end
end
#----------------SpitTest.rb
require 'test/unit'
require 'spit'

class SpitPileRules &lt; Test::Unit::TestCase
  def setup
    @pile = SpitPile.new( 2 )
  end
  def test_accepts_card_of_next_higher_rank
    assert @pile.play(3)
    assert_equal "2, 3", @pile.to_s
  end
  def test_accepts_card_of_next_lower_rank
    assert @pile.play(1)
    assert_equal "2, 1", @pile.to_s
  end
  def test_rejects_card_of_same_rank
    assert !@pile.play(2)
    assert_equal "2", @pile.to_s
  end
  def test_rejects_cards_of_non_consecutive_rank
    assert @pile.play(3)
    assert !@pile.play(1)
    assert_equal "2, 3", @pile.to_s
  end
end

class SpitPlayerRules &lt; Test::Unit::TestCase
  def setup 
    @player = Player.new(self)
    #Game double's state
    @pile_one = [7]
    @pile_two = [7]
    @stock = []
  end
  def test_run_without_draw
    @player.hand = [ 2, 3, 4, 5, 6 ]
    @player.play
    assert_equal [7, 6, 5, 4, 3, 2] , @pile_one
  end
  def test_player_draws_when_hand_is_short
    @stock &lt;&lt; 2
    @player.hand = [3, 4, 5, 6]
    @player.play
    assert @stock.empty?, "player did not draw as expected"
  end

  # game methods
  def spit_on_one( card )
    @pile_one &lt;&lt; card
  end
  def draw
    @stock.pop
  end
  def draw?
    ! @stock.empty?
  end 
end
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114063814716924714?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114063814716924714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114063814716924714' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114063814716924714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114063814716924714'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/02/tdding-card-game-part-3.html' title='TDDing a Card Game part 3'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-114002133292869974</id><published>2006-02-15T08:34:00.000-08:00</published><updated>2006-02-16T10:35:07.100-08:00</updated><title type='text'>TDDing a Card Game part 2</title><content type='html'>&lt;div&gt;
In the last entry I wrote a pretty simple class, SpitPile. It is responsible for enforcing the rules for playing a card in the card game Spit. 
&lt;/div&gt;
&lt;div&gt;
I received some feedback from Jim Hughes via the TDD yahoogroup. Jim kindly pointed out a corollary to the TDD rule "Only write code to pass a failing test". His corollary is "Always delete production code  when it won't break a test". Then he suggested a place in the SpitPile where I could apply this corollary. In SpitPile#in_sequence? I have this
&lt;pre&gt;
def in_sequence?(card) 
  (card != top_card) and ((card - top_card).abs == 1)
end
&lt;/pre&gt;
What I noticed, with Jim's guidance, is the logical duplication in that snippet. So I removed it and the tests still passed. Mmm, feel that green bar goodness.
&lt;/div&gt;
&lt;div&gt;
Here is the code for SpitPile in its entirety
&lt;pre&gt;
class SpitPile
  def initialize( first_card )
    @pile = [ first_card ]
  end
  def play( card )
    if in_sequence?(card)
      @pile &lt;&lt; card
      return true
    end
    false
  end
  def to_s
    @pile.join(', ')
  end
  def top_card
    @pile.last
  end
&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;&lt;pre&gt;
  def in_sequence?( card )
    (card - top_card).abs == 1
  end&lt;/pre&gt;&lt;/span&gt;
&lt;pre&gt;
end
&lt;/pre&gt;
and the tests
&lt;pre&gt;
class SpitPileRules &lt; Test::Unit::TestCase
  def setup
    @pile = SpitPile.new( 2 )
  end
  def test_accepts_card_of_next_higher_rank
    assert @pile.play(3)
    assert_equal "2, 3", @pile.to_s
  end
  def test_accepts_card_of_next_lower_rank
    assert @pile.play(1)
    assert_equal "2, 1", @pile.to_s
  end
  def test_rejects_card_of_same_rank Okay I'm stuck. I can't c
    assert !@pile.play(2)
    assert_equal "2", @pile.to_s
  end
  def test_rejects_cards_of_non_consecutive_rank
    assert @pile.play(3)
    assert !@pile.play(1)
    assert_equal "2, 3", @pile.to_s
  end
end
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
Onward. I think I'm going to work on a Game object to manage the flow of pay. Spit is not turn based so I'm thinking I might have to do some threading magic. That is notoriously difficult to test, but I'm not sure I'll need it yet.
&lt;/div&gt;
&lt;div&gt;
Start with a test. Okay, I'm stuck. I can't think of a simple test for Game without going immediately to a Player, but I did come up with this test for Player
&lt;pre&gt;
class SpitPlayerRules &lt; Test::Unit::TestCase
  def test_run_without_draw
    player = Player.new(self)
    player.hand = [ 2, 3, 4, 5, 6 ]
    @pile_one = [7]
    @pile_two = [7]
    player.play
    assert_equal [7, 6, 5, 4, 3, 2] , @pile_one
  end
end
&lt;/pre&gt;
This test assumes that player will modify SpitPlayerRules@pile_one which begs the question, how? This makes me think about the interaction between Player and Game. I don't have a Game object yet, but Ruby's 'duck' typing allows me to pass the test class to the Player and have it respond to the messages that Game should respond to. Incidentally this is known as the &lt;a href="http://tap.testautomationpatterns.com:8080/Self%20Shunt.html"&gt;Self-Shunt pattern&lt;/a&gt;. I often start with this and later refactor to use a real or mock version of the object. 
&lt;/div&gt;
&lt;div&gt;
What should it respond to? It seems to me that Player only needs to be able to 'spit' on a pile to pass this test. First I'll, wait, always run the test first to watch it fail. Okay it threw a NameError which means I haven't defined a Player class yet. Next it'll need a constructor with one parameter, an accessor for @hand, and a method 'play'. With that in place
&lt;pre&gt;
class Player
  attr_accessor :hand
  def initialize( game )
  end
  def play
  end
end
&lt;/pre&gt;
 the test is now failing as expected.
&lt;/div&gt;
&lt;div&gt;
I'm thinking the simplest thing that could possibly work is
&lt;pre&gt;
def initialize( game )
  @game = game
end
def play
  while(!@hand.empty?)
    @game.spit_on_one(@hand.pop)
  end
end
&lt;/pre&gt;
I'm assuming that game has a method 'spit_on_one'that takes a card. I'll make the SpitPlayerRules class do that for now. 
&lt;pre&gt;
def spit_on_one( card )
  @pile_one &lt;&lt; card
end
&lt;/pre&gt;
I'll run the tests. Green bar. 
&lt;/div&gt;
&lt;div&gt;
Now I can think of a few more tests that would help flesh out the interface between Game and Player. 
&lt;ul&gt;
&lt;li&gt;What happens when player makes an invalid move?&lt;/li&gt;
&lt;li&gt;How does Player draw from its stock pile?&lt;/li&gt;
&lt;li&gt;How does Player get notified of the end of game play?&lt;/li&gt;
&lt;li&gt;Does player notify Game when its out of cards?&lt;/li&gt;
&lt;/ul&gt;
All of these questions to answer and I'm out of time to write this. I'll ponder them. Maybe somebody like Jim will virtual pair with me again, and help me figure out where to go next. Until next time here is the code listing.
&lt;pre&gt;
#--------------------------Spit.rb
class SpitPile
  def initialize( first_card )
    @pile = [ first_card ]
  end
  def play( card )
    if in_sequence?(card)
      @pile &lt;&lt; card
      return true
    end
    false
  end
  def to_s
    @pile.join(', ')
  end
  def top_card
    @pile.last
  end
  def in_sequence?( card )
    (card - top_card).abs == 1
  end
end

class Player
  attr_accessor :hand
  def initialize( game )
    @game = game
  end
  def play
    while(!@hand.empty?)
      @game.spit_on_one(@hand.pop)
    end
  end
end
#-----------------SpitTest.rb
require 'test/unit'
require 'spit'

class SpitPileRules &lt; Test::Unit::TestCase
  def setup
    @pile = SpitPile.new( 2 )
  end
  def test_accepts_card_of_next_higher_rank
    assert @pile.play(3)
    assert_equal "2, 3", @pile.to_s
  end
  def test_accepts_card_of_next_lower_rank
    assert @pile.play(1)
    assert_equal "2, 1", @pile.to_s
  end
  def test_rejects_card_of_same_rank
    assert !@pile.play(2)
    assert_equal "2", @pile.to_s
  end
  def test_rejects_cards_of_non_consecutive_rank
    assert @pile.play(3)
    assert !@pile.play(1)
    assert_equal "2, 3", @pile.to_s
  end
end

class SpitPlayerRules &lt; Test::Unit::TestCase
  def test_run_without_draw
    player = Player.new(self)
    player.hand = [ 2, 3, 4, 5, 6 ]
    @pile_one = [7]
    @pile_two = [7]
    player.play
    assert_equal [7, 6, 5, 4, 3, 2] , @pile_one
  end

  # game methods
  def spit_on_one( card )
    @pile_one &lt;&lt; card
  end
end
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-114002133292869974?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/114002133292869974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=114002133292869974' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114002133292869974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/114002133292869974'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/02/tdding-card-game-part-2.html' title='TDDing a Card Game part 2'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-113941428082524889</id><published>2006-02-08T07:53:00.000-08:00</published><updated>2006-02-08T09:10:30.806-08:00</updated><title type='text'>TDDing a Card Game part 1</title><content type='html'>&lt;div&gt;
In my &lt;a href="http://anthonysseblog.blogspot.com/2006/02/why-im-starting-to-blog.html"&gt;previous post&lt;/a&gt; I committed to writing an entry a week in this blog. Coming up with content is hard! Of course since I've called this my Software Engineering blog I've narrowed the topic down somewhat.
&lt;/div&gt;
&lt;div&gt;
One important technique in any programmer's toolkit is &lt;a href="http://c2.com/cgi/wiki?TestDrivenDevelopment"&gt;Test Driven Development&lt;/a&gt;. Contrary to the name, TDD is a Design technique. We write a test to specify and constrain the problem at hand. Then after watching it fail, we write the simplest code that will cause the test to pass. Finally, and most importantly we refactor to eliminate any duplication that we created in the previous step. We do this loop several times and soon we've designed and coded a piece of software. For the next few entries I'm going to use TDD to create a card game.
&lt;/div&gt;
&lt;div&gt;
&lt;a href="http://en.wikipedia.org/wiki/Spit_(card_game)"&gt;Spit, also called Speed&lt;/a&gt;, is a card game I used to play when I was younger, though I always played the &lt;a href="http://en.wikipedia.org/wiki/Spit_(card_game)#Version_with_five_card_hand"&gt;five card hand variant&lt;/a&gt;. I'm going to focus the five card hand variant because it's what I know. Others have programmed versions of  &lt;a href="http://www.alivegames.com/speed/"&gt;the&lt;/a&gt; &lt;a href="http://www.ossiemanners.co.uk/"&gt;game&lt;/a&gt; before. I never have though, so this ought to be fun.
&lt;/div&gt;
&lt;div&gt; 
The layout is as follows:
&lt;pre&gt;
 stockpile ------&gt; 15 cards

10 cards    1 card          1 card    10 cards &lt;---- spit piles and spit reserves

 stockpile ------&gt; 15 cards
&lt;/pre&gt;
The object of the game is to place all of your cards from your stockpile into the spit piles before the other player. This is not a turn based game. You may only have five cards in your hand at time. Cards of the next higher or lower rank may be played from your hand to either spit pile. If both players are stuck you simultaneously flip the top card from the spit reserves on to the spit pile. 
&lt;/div&gt;
&lt;div&gt;
As this post is already pretty long we'll just tackle the rules for playing a card on the spit pile. My language of choice at the moment is &lt;a href="http://ruby-lang.org"&gt;ruby&lt;/a&gt;. Ruby's Test::Unit is the ruby member of the xUnit family.
&lt;/div&gt;
&lt;div&gt;
We start with a test.
&lt;pre&gt;
require 'test/unit'

class SpitPileRules &lt; Test::Unit::TestCase
  def test_accepts_card_of_next_higher_rank
    @pile = SpitPile.new( 2 )
    assert @pile.play(3)
    assert_equal "2, 3", @pile.to_s
  end
end
&lt;/pre&gt;

I've named this test case SpitPileRules because it is specifying the rules of play for the spit pile. The first test shows we can play a card of higher rank. At the moment cards are represented as numbers because in Spit we don't care about the suite. We're checking the contents by looking at the string representation of the pile. Also, we expect the SpitPile#play to return a boolean showing success. The next step is to pass this test as quickly as possible, wait first we run it to watch it fail. Okay, now we can pass it.

&lt;pre&gt;
class SpitPile
  def initialize( first_card )
  end
  def play ( card )
    true
  end
  def to_s 
   "2, 3"
  end
end
&lt;/pre&gt;
That passes. Now we refactor to remove duplication. What duplication, you might ask. Well, the string in SpitPile#to_s duplicates the expected value in SpitPileRules#test_accepts_card_of_next_higher_rank. So I'll replace it with a member variable, and make sure the variable is populated correctly.
&lt;pre&gt;
class SpitPile
  def initialize( first_card )
    @pile = [ first_card ]
  end
  def play ( card )
    @pile &lt;&lt; card
    true
  end
  def to_s 
    @pile.join(', ')
  end
end
&lt;/pre&gt;
Run the tests, and it still passes. What happens when we add a card of lower rank? Let's write the test.
&lt;pre&gt;
def test_accepts_card_of_next_lower_rank
  @pile = SpitPile.new( 2 )
  assert @pile.play(1)
  assert_equal "2, 1", @pile.to_s
end
&lt;/pre&gt;
Okay, let's make that pass. Wait, first I'll run the test, and it passes. That's fine, that happens very rarely to me, but as SpitPile stands it passes this new test. On to the next test. We could either check if it rejects cards of non consecutive rank or if it rejects cards that are of the same rank. I think I'll do the same rank first.
&lt;pre&gt;
def test_rejects_card_of_same_rank
  @pile = SpitPile.new( 2 )
  assert !@pile.play(2)
  assert_equal "2", @pile.to_s
end
&lt;/pre&gt;
Run that, and it fails. Good. Now we make it pass.
&lt;pre&gt;
def play ( card )
  if card != @pile.first
    @pile &lt;&lt; card
    return true
  end
  false
end
&lt;/pre&gt;
Passed. Okay, now we have an opportunity to refactor. This time we see duplication in the test specifically all three tests have: &lt;pre&gt;@pile = SpitPile.new( 2 )&lt;/pre&gt;
Let's factor that out into a setup method.
&lt;pre&gt;
class SpitPileRules &lt; Test::Unit::TestCase
  def setup
    @pile = SpitPile.new( 2 )
  end
  def test_accepts_card_of_next_higher_rank
    assert @pile.play(3)
    assert_equal "2, 3", @pile.to_s
  end
  def test_accepts_card_of_next_lower_rank
    assert @pile.play(1)
    assert_equal "2, 1", @pile.to_s
  end
  def test_rejects_card_of_same_rank
    assert !@pile.play(2)
    assert_equal "2", @pile.to_s
  end
end
&lt;/pre&gt;
After running tests I'm sure it's still passing so I will move on to non consecutive cards.
&lt;pre&gt;
def test_rejects_cards_of_non_consecutive_rank
  assert @pile.play(3)
  assert !@pile.play(5)
  assert_equal "2, 3", @pile.to_s
end
&lt;/pre&gt;
It fails. Now we can make it pass.
&lt;pre&gt;
def play ( card )
  if (card != @pile.first) and ((card - @pile.first).abs == 1)
    @pile &lt;&lt; card
    return true
  end
  false
end
&lt;/pre&gt;
That passes, but I just noticed that it might not pass if I change that case like this:
&lt;pre&gt;
def test_rejects_cards_of_non_consecutive_rank
  assert @pile.play(3)
  assert !@pile.play(1)
  assert_equal "2, 3", @pile.to_s
end
&lt;/pre&gt;
It doesn't. The reason is I'm adding card to the end of the pile with &lt;&lt;, but I'm checking against &lt;pre&gt;@pile.first&lt;/pre&gt; so I'll change that to &lt;pre&gt; @pile.last&lt;/pre&gt; and we're green. Now it's time to refactor. The obvious duplication of @pile.last can be factored out to something more meaningful.
&lt;pre&gt;
def play( card )
  if (card != top_card) and ((card - top_card).abs == 1)
    @pile &lt;&lt; card
    return true
  end
  false
end
def top_card
  @pile.last
end
&lt;/pre&gt;
Tests are still green. Next we'll clarify what those conditions mean.
&lt;pre&gt;
def play( card )
  if in_sequence?(card)
    @pile &lt;&lt; card
    return true
  end
  false
end
def in_sequence?(card)
  (card != top_card) and ((card - top_card).abs == 1)
end
&lt;/pre&gt;
Okay. I've spent about two hours on writing this article including about 15 minutes of coding. I see a few directions I can go from here. I think SpitPile#in_sequence? really doesn't belong to SpitPile. It seems like it should be on Card, or Deck or something like that. Also, I'm not entirely comfortable with to_s. I think it may be tying the rules of a SpitPile to closely too a UI, but it will do for now. 
Now that we have SpitPile should we create a Player class that can interact with SpitPile, or a Game class that controls the flow of the game around SpitPile? Do we make some of the other piles as independent classes? I'll decide soon and work on it in the next entry.
&lt;/div&gt;
&lt;div&gt; Thanks for following along. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-113941428082524889?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/113941428082524889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=113941428082524889' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/113941428082524889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/113941428082524889'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/02/tdding-card-game-part-1.html' title='TDDing a Card Game part 1'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21814360.post-113880969209976114</id><published>2006-02-01T07:19:00.000-08:00</published><updated>2006-02-08T07:25:17.536-08:00</updated><title type='text'>Why I'm Starting to Blog</title><content type='html'>&lt;div&gt;The other day I purchased &lt;a href="http://www.pragmaticprogrammer.com/titles/mjwti/index.html"&gt;My Job Went To India (And All I Got Was This Lousy Book) 52 Ways To Save &lt;span style="font-style:italic;"&gt;Your&lt;/span&gt; Job&lt;/a&gt; by &lt;a href="http://www.chadfowler.com"&gt;Chad Fowler&lt;/a&gt;. It's a great book on how to &lt;q&gt;architect your career&lt;/q&gt; for software engineers. Each chapter ends with an &lt;span style="font-style:italic;"&gt;Act On It&lt;/span&gt; section that encourages you to apply the advice provided. My shiny new blog is a result of an &lt;span style="font-style:italic;"&gt;Act On It&lt;/span&gt;.&lt;/div&gt;

&lt;div&gt;Chapter 12 is about finding a mentor, and the &lt;span style="font-style:italic;"&gt;Act On It&lt;/span&gt; section encourages you to &lt;q&gt;Mentor Yourself&lt;/q&gt; by choosing someone you admire as a role model, list and rank their most important attributes, and rate yourself as they would rate you on those attributes. Then you can determine what you should work on.&lt;/div&gt;

&lt;div&gt;I did this activity, and determined the attribute of &lt;a href="http://www.xprogramming.com/"&gt;my chosen mentor&lt;/a&gt; that I most need to work on is a prolific writing habit. This includes &lt;a href="http://www.xprogramming.com/Blog"&gt;blogging&lt;/a&gt;, &lt;a href="http://www.xprogramming.com/xpmag/index.htm"&gt;web articles&lt;/a&gt;, &lt;a href="http://groups.yahoo.com/group/extremeprogramming/messagesearch?query=RonJeffries%40&amp;submit=Go&amp;charset=ISO-8859-1"&gt;contributions to mailing lists&lt;/a&gt;, and &lt;a href="http://www.amazon.com/exec/obidos/search-handle-url/index=books&amp;field-author-exact=Ron%20Jeffries&amp;rank=-relevance%2C%2Bavailability%2C-daterank/102-7502061-5252117"&gt;books&lt;/a&gt;. I've resolved to do the following:&lt;ul&gt;&lt;li&gt;Get a blog &amp;lt;Check /&amp;gt;&lt;/li&gt;&lt;li&gt;Post at least once a week to said blog&lt;/li&gt;&lt;li&gt;Respond relevantly to at least one mailing list post per day&lt;/li&gt;&lt;li&gt;Take the next opportunity to write a technical article&lt;/li&gt;&lt;/ul&gt;
So there you have it, why I'm starting to blog in a nutshell. Many thanks to Chad for the book that will change my career.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21814360-113880969209976114?l=anthonysseblog.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://anthonysseblog.blogspot.com/feeds/113880969209976114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=21814360&amp;postID=113880969209976114' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/113880969209976114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21814360/posts/default/113880969209976114'/><link rel='alternate' type='text/html' href='http://anthonysseblog.blogspot.com/2006/02/why-im-starting-to-blog.html' title='Why I&apos;m Starting to Blog'/><author><name>Anthony Moralez</name><uri>http://www.blogger.com/profile/18058307711677371125</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15890337335712738325'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry></feed>