飛車と角の利き(Ruby)

問題:

飛車と角を将棋盤(9×9)の上にひとつづつおきます。このとき、飛車か角によって(相手の)駒が取られる位置を、飛車と角の「利き」ということにします。
飛車の「利き」の上に角があるとき、その先の飛車の「利き」は(角にさえぎられて)ありません。角の場合も同様です。
飛車と角は重なりません。
飛車と角が採りうる位置をすべて採るとき、「利き」の総和は何個になるでしょうか。

 
Ruby で解いてみます。総当り法で、特に何のくふうもしていません。

class Field
  def clear
    a = Array.new(11, 1)
    @field = Array.new(9) {[1] + [0] * 9 + [1]}
    @field.unshift(a)
    @field.push(a)
  end
  
  def set(x, y, koma)
    @field[y][x] = koma
  end
  
  def get(x, y)
    @field[y][x]
  end
  
  def count
    counter = 0
    move_koma do |x, y|
      counter += 1 if get(x, y) == 4
    end
    counter
  end
  
  def set_kiki(x, y, dir)
    loop do
      x += dir[0]
      y += dir[1]
      a = get(x, y)
      return if a == 1 or a == 2 or a == 3
      set(x, y, 4)
    end
  end
end

def move_koma
  1.upto(9) do |y|
    1.upto(9) {|x| yield(x, y)}
  end
end


f = Field.new
counter = 0
move_koma do |xh, yh|
  move_koma do |xk, yk|
    next if xh == xk and yh == yk
    f.clear
    f.set(xh, yh, 2)
    f.set(xk, yk, 3)
    
    #飛車
    [[-1,  0], [1,  0], [0, -1], [0, 1]].each {|dir| f.set_kiki(xh, yh, dir)}
    #角
    [[-1, -1], [-1, 1], [1, -1], [1, 1]].each {|dir| f.set_kiki(xk, yk, dir)}
    
    counter += f.count
  end
end
puts counter    #=>149424

わざわざ(一部)オブジェクト指向プログラミングで解く必要はないのですが、この方が(自分に)見やすいかと思ってこうしました。

将棋盤(@field)の周囲には番兵を置いてあります。0 が空白、1 が番兵、2 が飛車、3 が角、4 が「利き」です。
 

 
 
よく似た問題に、チェスの「エイト・クイーン問題」というのがあります。過去記事で扱っているので、よろしければ御覧下さい。