LoginSignup
10

More than 5 years have passed since last update.

Rubyでリバーシ(オセロ)

Last updated at Posted at 2014-11-03

はじめに

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

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

・参考
【プログラミング】オセロを1時間で作ってみた【実況解説】

ソース

イメージ

othelo.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_rooty_rootに保存する、存在しなければ置けないとしfalseを返す
x_rooty_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を1増やしtrueを返す
pass_countが2以上の場合それは白、黒お互い置けないを意味する

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_xmax_yに保存しそれを使い一番ひっくり返せる場所をaround_checkmax_countで保存したmax_putを使い選択する
また10%の確率で置ける場所の一番左上を選択する

まとめ

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10