Rule #1 of TDD, if it's hard to test, you've probably got a problem in the code.

Rule #2 of TDD, most code is hard to test.

Lemma #1 : Most code has problems (follows from Rule #2 and Rule #1).

----------

I haven't looked at this code thoroughly yet, my guess, however, is that you
have only two classes for a problem which probably desires more. I have a set of
Maxims about programming I use often, but one of the most important is one I
stole from the greats, it's called "SOLID" -- and the important bit for us to
consider is the "S"; the "Single Responsibility Principle"

The idea of the SRP is that each class should have precisely one responsibility
(but crucially, not necessarily one _role_) in the system. Here, we have three
classes(ish) representing _all_ of the code necessary to play connect four. To
see why this is a problem, let's look at a breakdown of a problem in prose:

-----

To play Connect Four, I first need a board, a board has many positions,
arranged in a grid.  Each position has neighbors. There are precisely two
players, and each have many positions.  The positions on the board specify a
subset of "fillable" positions, starting with an arbitrary player, each takes
turns choosing one of the fillable positions and adding a position to it's
position-set.  The board then recalculates it's position set according to the
new set of "taken" positions by adding the position directly above the taken
position, and adding the taken position to it's set of "Filled" positions. Any
position that is not Filled is Empty. An arbitrator can see that one of the
players has won when they see that one of the player owns four positions in a
horizontal, vertical, or diagonal row.  

-----

So, we can try to parse that, and read out the actors of the system -- an Actor
is a particular responsibility that needs filling, I'll go through and highlight
the actors now:

-----

To play Connect Four, I first need a *board*, a board has many *positions*,
arranged in a grid. Each position has neighbors. There are precisely two
*players*, and each have many positions.  The positions on the board specify a
subset of *"fillable" positions*, starting with an arbitrary player, each
takes turns choosing one of the fillable positions and adding a position to it's
position-set.  The board then recalculates it's position set according to the
new set of "taken" positions by adding the position directly above the taken
position, and adding the taken position to it's set of *"Filled" positions*. Any
position that is not Filled is *Empty*. *An arbitrator* can see that one of the
players has won when they see that one of the player owns four positions in a
horizontal, vertical, or diagonal row.

-----

So we can see that the Actors of the system are:

* The Board
* The Positions
  - A subconcept of "Fillable" positions
  - A subconcept of "Filled" positions
  - A subconcept of "Empty" positions
* The Players
  - A subconcept of the AI-player
* The Arbitrator

So far, I'm counting 4 or 5 (I'm not sure how I want to model Fillable positions
yet) actors. Since we're building an AI, we can treat it as a special case of
the Player model.

At this point, We can go back and look at the relationships between models, I
won't highlight them as before, but they look a bit like:


* The Board
  - Has-many positions
    * Has-subset of "Filled" positions
  - Belongs-to two players and an arbitrator
  
* The Positions
  - Has-many Neighbors
  - Belongs-to a Player or noone

* The Players
  - Has-many positions
  - Can see the board -- and thus other player's positions.
  
* The Arbitrator
  - Can see the whole board -- and thus all player positions.

After looking at the relationships, we can start to think about responsibilities
for each model -- We can see that the board will be primarily an information
"Source" -- where we pull information about what positions are
fillable/empty/filled etc. 

A position is a bit different, players will be manipulating them often, we will
need to know if a position is filled or fillable or empty, we'll need to have
the ability to 'take' a filled position, and we'll need to be able to see which
player owns the position.

The players are our "primary" actors, most of the interaction with the program
is through them, they should probably be able to identify the set of fillable
positions, and give us a method for choosing one and adding it to the owned-set
of positions they have. For the AI player, we might want to model a "Brain"
which makes the decision to choose from the given set of fillable positions and
the state of the board which position to choose.

Finally, the Arbitrator is really just encapsulating the "win" condition, he
shoud have a method like `#check!` which returns either false or the player who
won the game[1].

So, already we can see there is a little more apparent complexity (inasmuch as
there are probably 5 or 6 classes here), but less _actual_ complexity, since
each object is only doing one thing. I might therefore start w/ tests that just
lay out the API, like:

````ruby

# in board_spec.rb
describe Board do
  it { should respond_to :positions }
  it { should respond_to :fillable_positions }
  it { should respond_to :players } 
end

#in position_spec.rb
describe Position do
  it { should repsond_to :filled? }
  it { should respond_to :empty? }
  it { should respond_to :owner }
  it { should respond_to :fillable } 

  describe "a filled/taken position" do
    #intentionally blank
  end

  describe "an empty position" do
    #intentionally blank
  end
end

#etc

````

These `respond_to` tests are largely just notes, they help me to remember what
the API is as I'm developing, sometimes I leave them in, there are a lot of
arguments as to whether or not they're useful/useless/harmful. I like them.
Specifically, I like to keep them at the top of my specs, so that I can
at-a-glance see what the API of my object is, which helps later when mocking or
even just using my library/app.

Now we can start speccing. Let's look at the position spec

````ruby

#in position_spec.rb
describe Position do
  it { should repsond_to :filled? }
  it { should respond_to :empty? }
  it { should respond_to :owner }
  it { should respond_to :fillable? } 

  let (:position) { Position.new } 
  let (:player) { double("Player 1") } 
  let (:board) { double("Board") }

  subject { position } 

  describe "a filled/taken position" do
    before do
      position.stub(:owner).and_return(player) 
    end

    it { should_not be_empty } 
    it { should_not be_fillable } 
    it { should be_filled } 
  end

  describe "an empty position" do
    it { should be_empty } 
    its(:owner) { should be_nil } 

    context "an empty, unfillable position" do
      before do
        #appropriate mocking to make the board specify this position as
        #not-fillable
      end

      it { should_not be_fillable }  
    end

    context "an empty, fillable position" do
      before do
        #appropriate mocking to make the board specify this position as
        #fillable
      end

      it { should be_fillable } 
    end
  end
end

````

Now hopefully you can see how easy it is to spec that model, and further, the
implementation of those things should be pretty obvious -- I used mocks to avoid
instantiating a dependency, instead just noting that in one context, the
`#owner` method returns _something_, and in another it returns nothing. I used
context to specify the sub-condition of fillability. Importantly -- I haven't
written any code yet, just specified how this class should behave, and what API
it should support. I can now build the Position class in total isolation of
everything else. Rinse and repeat to build up the other classes, and vois la, a
really nice OO design that will be easy to maintain and well-tested! A FOSS
Maintainers Dream!

------

Hopefully that helps elucidate a bit, I want to add the disclaimer that I
didn't run any of this through an interpreter or anything, so there might be
syntax bugs and stuff. Take everything with a grain of salt.

/Joe


--------------------------------------------------------------------------------

[1] This is a pretty common technique, in Haskell they call it the "Maybe"
datatype, elsewhere it's called the "Nullable Value" pattern. The idea is that
you can return either "Nothing" -- which means nothing happened, or a specific
sort of "Something", which acts-as-true, and also carries information about what
_kind_ of truth that is.