Here is my solution.
Pastie: http://pastie.org/377536
The pastie still has the comment on the distances function as
returning the distance between two hexes, but I changed this to return
an array of all distances from some position, since the breadth-first
search was already calculating this anyway.


class Hex
 attr_accessor :neighbours,:distance
 def initialize(row,col,rows,cols)
  @neighbours =
[[-1,-1],[-1,0],[0,-1],[0,1],[1,0],[1,1]].map{|r,c|[row+r,col+c]}.select{|r,c|
r>=0 && c>=0 && r<rows && c<cols}
  @obstructed = col==3 && row!=rows-1  ||  col==6 && row!=0 # double barrier
 end
 def obstructed?; @obstructed ;end
end

class HexBoard < Array
 def initialize(rows=9, cols=9)
   super(rows) {|row| Array.new(cols) {|col| Hex.new(row,col, rows,cols) }}
 end
 # Distance from position to each hex
 def distances(position,&block)
   each{|row| row.each{|hex| hex.distance = nil } }
   bfs_distance([position],0, &block);
   map{|row| row.map &:distance }
 end
 # Breadth-first search distance
 def bfs_distance(hexes,dist, &block)
   q = []
   hexes.map{|r,c| self[r][c] }.each{|hex|
     next if hex.distance || block_given? && yield(hex)
     hex.distance = dist
     q += hex.neighbours
   }
   bfs_distance(q.uniq,dist+1, &block) unless hexes.empty?
 end
 # Draw solution
 def draw(from=[4,4],&block)
   distances(from,&block).each_with_index{|dists,row| puts "#{row}:#{'
'*(size - row)}#{dists.map{|x|x||'#'}.join ' '}\n" }
 end
end

board = HexBoard.new
board.draw
board.draw([0,0],&:obstructed?)