問題:
飛車と角を将棋盤(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 が「利き」です。
プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問
- 作者: 増井敏克
- 出版社/メーカー: 翔泳社
- 発売日: 2015/10/16
- メディア: Kindle版
- この商品を含むブログ (9件) を見る
よく似た問題に、チェスの「エイト・クイーン問題」というのがあります。過去記事で扱っているので、よろしければ御覧下さい。