Problem:
問題文

お菓子の魔女 CHARLOTTE は巴マミとクッキーゲームを楽しんでいる．クッキーゲームは 8\times 8 の格子状に区切られたテーブルクロスの上にチーズクッキーとチョコレートクッキーを置いて行われる．各格子には高々 1 個のチョコレートクッキーまたはチーズクッキーしか置くことはできない．

お菓子の魔女はチーズクッキーを，巴マミはチョコレートクッキーを交互に置いてゲームを行う．自分のクッキーを置いたあと，そのクッキーから上下左右斜めの各 8 方向について，置くクッキーとすでに置いていた自分のクッキーの間に相手のクッキーのみが直線に並んでいた場合に，その挟まれた相手のクッキーのすべてが自分のクッキーで置き換えられる．クッキーゲームのプレイヤーは自分のターンが回ってきた時，1 つ自分のクッキーを置くことができる．ただし，相手のクッキーを少なくとも 1 つ以上自分のクッキーに置き換えられなければならない．そのような置き場がない場合，自分のターンをパスをしなければならない．

お菓子の魔女も巴マミも考えるのが少々苦手である．そこで，回ってきたターン毎にそのターンの中で置き換えられるクッキーの数を最大化することを考えることにした．巴マミのターンのときに置き換えられるクッキーの数を最大にするようなクッキーを置く場所の候補が複数ある場合は，より上の場所を，それでも複数ある場合はより左の場所を選択することにした．また同様に，お菓子の魔女のターンのときに候補が複数ある場合はより下の場所を，それでも複数ある場合はより右の場所を選択することにした．

テーブルクロスに置かれたクッキーの状態が与えられるので，巴マミからはじめ，彼女たちがそこからクッキーゲームを行い，共に新たなクッキーが置けなくなるまでゲームを続けた時のテーブルクロスの上に置かれたクッキーの状態を求めよ．

入力形式

入力は以下の形式で与えられる．

s_{11} s_{12} ... s_{18}\\
s_{21} s_{22} ... s_{28}\\
...\\
s_{81} s_{82} ... s_{88}\\

s_{ij} はテーブルクロスに置かれたクッキーの初期状態を表す文字で，上から i 行目，左から j 列目の格子の状態を表す．チョコレートクッキーが置かれているときs_{ij}は 'o' であり，チーズクッキーが置かれているときは 'x', 何も置かれていないときは '.' となる．

出力形式

クッキーゲームが行われた後のテーブルクロスの上に置かれたクッキーの状態を，入力形式と同じ形式で出力せよ．

制約

s_{ij} は 'o', 'x', '.' のいずれかである．

入出力例

入力例 1

ooox....
.x......
ooo.....
........
........
........
........
........

出力例1

ooooo...
.o......
ooo.....
...o....
....o...
........
........
........

入力例 2

........
........
........
...ox...
...xo...
........
........
........

出力例 2

xxxxxxxx
xxxooxxx
xxxxooxx
xxxxxxxx
ooxxooox
ooxoooox
oxooooox
ooooooox

入力例 3

........
........
..ooo...
..oxo...
..ooo...
........
........
........

出力例 3

........
........
..ooo...
..ooo...
..ooo...
.....o..
......o.
........

Problem Setter: Flat35

Solution in Ruby (judge verdict: Accepted)

require 'pp'

class Reversi
  attr_accessor :width, :height, :turn, :board
  BLACK = 1
  WHITE = 2
  DX = [-1,-1,-1, 0, 0, 1, 1, 1]
  DY = [-1, 0, 1,-1, 1,-1, 0, 1]
  
  def initialize(width = 8, height = 8)
    @width = width
    @height = height
    @board = Array.new(@height).map!{Array.new(@width, 0)}
    @turn = BLACK
    @colornum = 2
  end

  def check(color=@turn)
    point = Struct.new(:x, :y);
    ar = []
    for i in 0..@height-1
      for j in 0..@width-1
        ar.push point.new(j, i) if put_stone(color, j, i, false) >= 1
      end
    end
    return ar
  end
  
  # 0 => もう置けない
  def next_color()
      turn = @turn
      @colornum.times{
        turn = (turn%2)+1
        return turn if check(turn).size > 0
      }
      return 0
  end
  
  # -1 => 置けない  0 => ゲーム終了  それ以外 => 次の手番
  def put(x, y)
    return 0 if @turn == 0
    if put_stone(@turn, x, y) then
      @turn = next_color
      return @turn
    end
    return -1
  end
  
  def put_stone(color, x, y, put = true) # putがfalseの時は置けるか調べるだけ
    point = Struct.new(:x, :y);

    return 0 if @board[y][x] != 0 # 置く場所をチェック
    queue = [point.new(x,y)]    # 石が変わる座標をqueueで持つ
    
    # 8方向を調べる
    8.times{|i|
      cnt = 0 # 返す石の数
      for j in 1..[@width,@height].max
        nx = x + DX[i] * j
        ny = y + DY[i] * j
        break if nx < 0 || nx >= @width || ny < 0 || ny >= @height # 配列外チェック
        break if @board[ny][nx] == 0                  # 石が無いなら次へ
        break if @board[ny][nx] == color && cnt == 0  # ひっくり返せないなら次へ
        if @board[ny][nx] == color then # ひっくり返せるなら、ひっくり返す
          for k in 1..cnt
            queue.push point.new(x+DX[i]*k, y+DY[i]*k)
          end
          break
        end
        cnt += 1
      end
    }
    
    revnum = queue.size-1 # 返す石の数
    

    if put then
      until queue.empty?  # 石を返す処理
        p = queue.shift
        @board[p.y][p.x] = color
      end
    end
    
    return revnum
  end
end


rev = Reversi.new

input = []
8.times{
  input.push gets.chomp.gsub('o', '1 ').gsub('x', '2 ').gsub('.', '0 ').split(nil).map(&:to_i)
}

rev.board = input

rev.turn = rev.next_color if rev.check.size <= 0

while rev.turn >= 1
  best = 0
  x = 0
  y = 0
  8.times{|i|
    8.times{|j|
      cnt = rev.put_stone(rev.turn, j, i, false)
      if (rev.turn == 2 && best <= cnt) || (rev.turn == 1 && best < cnt) then
        y = i
        x = j
        best = cnt
      end
    }
  }
  rev.put(x, y)
end

rev.board.each{|e|
  puts e.join.to_s.gsub('1', 'o').gsub('2', 'x').gsub('0', '.')
}