Rubyでリバーシ(オセロ)

#はじめに
Swiftでパズルゲーを作ろうと持っていたが
思いのほか手こずってしまい気分転換にRubyでリバーシを作ってみた

・環境
OSX10.9.5
ruby 2.0.0p481
terminalで起動

・参考
[【プログラミング】オセロを1時間で作ってみた【実況解説】](http://www.nicovideo.jp/watch/sm8391299)

#ソース
https://github.com/konpeto000/ruby-othelo

#イメージ
![othelo.gif](https://qiita-image-store.s3.amazonaws.com/0/57208/206f1768-addd-55d1-fe40-a3d49770f3d2.gif)

#解説
**initialize**
**color_choice**
**showBoard**
**player_put**
については割愛させていただきます

**around_check(nx,ny)**

    x_root = Array.new
    y_root = Array.new
    @dx_root = Array.new
    @dy_root = Array.new
    max_count = 0

    for j in 0..2
      for i in 0..2
        if @field[nx+i-1][ny+j-1] == -1 * $player_color
          x_root << i-1
          y_root << j-1
        end
      end
    end

    if x_root.length <= 0
      return false
    end

    for count in 0..x_root.length - 1

      empty_flag = 0
      x = x_root[count]
      y = y_root[count]
      dx = nx
      dy = ny
      while 1
        dx += x
        dy += y

        if dx > 8 || dy > 8 || dx < 1 || dy < 1
          empty_flag = 1
          break
        end

        if @field[dx][dy] == 0
          empty_flag = 1
          break
        end
        if @field[dx][dy] == $player_color
          break
        end

      end

      if empty_flag == 0
        max_count += 1
        @dx_root << x_root[count]
        @dy_root << y_root[count]
      end

    end
      
    if @dx_root.length > 0
      $max_put << max_count
      return true
    else
      return false
    end

石を置きたい場所の周りに自分の色とは違う色が存在するなら
その位置を`x_root`と`y_root`に保存する、存在しなければ置けないとし`false`を返す
`x_root`と`y_root`から要素を取り出し各方向にひっくり返せる石が存在するかどうかを調べる
探索範囲がボード外、途中に空白が存在する場合その方向は無効とし保存せず
終端に自分の色が存在する場合のみその方向の位置を保存する

*CPUに関する条件*
`max_count`はその位置に置いたときどれだけ石をひっくり返せるか数える変数
またその値を`max_put`の配列に入れる

**stone_put(nx,ny)**

    @field[nx][ny] = $player_color

    for count in 0..@dx_root.length - 1
      x = @dx_root[count]
      y = @dy_root[count]
      dx = nx
      dy = ny
      while 1
        dx += x
        dy += y

        if @field[dx][dy] == $player_color
          break
        end

        @field[dx][dy] = -1 * @field[dx][dy]
      end
    end
自分が置く場所に自分の色の石をおく
`around_check`で保存した変数を使いひっくり返せる方向をすべてを自分の色にする

**pass_check**

    for j in 1..SQUARES
      for i in 1..SQUARES
        if @field[i][j] != 0
          next
        end
        if around_check(i,j)
          return false
        end
      end
    end

    $pass_count += 1

    return true

`around_check`関数をつかい自分が置ける石があるばあい置けるとし`false`を返す
そうでない場合`pass_count`を１増やし`true`を返す
`pass_count`が２以上の場合それは白、黒お互い置けないを意味する

**gameset**

    w_count = 0
    b_count = 0

    for j in 1..SQUARES
      for i in 1..SQUARES
        case @field[i][j]
        when 1
          w_count += 1
        when -1
          b_count += 1
        end
      end
    end
    

    if w_count == b_count
      print "W:#{w_count} B:#{b_count} Draw!\n" 
      return true
    end
    
    if w_count > b_count
      print "W:#{w_count} B:#{b_count} White win!\n"
    else
      print "W:#{w_count} B:#{b_count} Black win!\n"
    end

`pass_count`が2以上の場合呼ばれる
フィールド上の白、黒石の個数を数え石の多い方が勝ちと表示する
また引き分けも存在するのでその場合も追加しておく

**cpu**

    $max_put = Array.new
    max_x = Array.new
    max_y = Array.new
    random = rand(100)

    if $pass_count >= 2
      return true
    end

    if $player_color == 1
      if pass_check
        p "White PASS!"
        return false
      end
      
    else
      if pass_check
        p "Black PASS!"
        return false
      end
    end

    $pass_count = 0

    for j in 1..SQUARES
      for i in 1..SQUARES
        if @field[i][j] != 0
          next
        end
        if around_check(i,j)
          max_x << i
          max_y << j
        end
      end
    end

    $max_put.shift
    if random > 10
      n = $max_put.index($max_put.max)
    else
      n = 0
    end
      

    if around_check(max_x[n],max_y[n])
      stone_put(max_x[n],max_y[n])
    end

    p "CPU put (#{max_x[n]},#{max_y[n]})"

    return false
    end

プレイヤーと同じ処理をただ自動でやってもらうだけなのだが
石を置く選択だけちょっと考えてもらうことにした
まず、置ける場所を`max_x`と`max_y`に保存しそれを使い一番ひっくり返せる場所を`around_check`の`max_count`で保存した`max_put`を使い選択する
また10％の確率で置ける場所の一番左上を選択する

#まとめ
前もそうだったが作っている最中はただ動けばいいと考え書いているのだが
もう一度見直すとすごくわかりにくく汚いなぁと感じる
相手に読んでもらえるように綺麗に書くことを心がけたい