読者です 読者をやめる 読者になる 読者になる

餅屋LGTM

餅つきのあとの静けさ

Rubyでオセロ 〜その3〜

棋譜の読み込みまで

棋譜については作るひつようもあまりないかなとは思ったのだけれども打てる場所がなくなって終わる試合などの棋譜を残せば後で変更を加えたときのデバッグが楽になるだろうと思って作ることにした

1. 棋譜の形式を考える

例えば エラー - OWiki のページの棋譜

e6f4c3c4d3d6e3c2b3d2 f3c5b4f7b6c6b5f2e7f5e2f6c7e8d1a4a5a6d7a3g3h3b2a1g6c8d8f8g4f1e1b1g1h4g5h5h6h7g7c1g2h8g8h1h2a7b7a2a8b8
e6f4c3c4d3d6e3c2b3d2f3b4f5e2e1f1g1f2g3e7 b1a3c5b5a6g4f6h3f7c6c7g6g5d7h6b6e8c8h5h4h2g8f8d8a5d1c1a4a2h7h8g7b8b7a7a8g2h1a1b2

のように一行にまとめられていて複数記載されていたりするが人間が読むこともあるかもしれないので

c4
c3
f5
b4
b3
...

のような形にする

2. 棋譜を保存する

1. 配列に指し手を保存する
  1. 棋譜を保存する配列の作成
  2. put_stoneメソッドに引数moveを追加
  3. human,comそれぞれからput_stoneを呼び出すときに指す座標を引数として与える
...

def start_game
  ...
  @record = [] #棋譜を保存する配列
  ...
end

def put_stone(cell, move) #引数にmoveを追加
  ...

  @record.push(move)

  ...

end
2. ゲーム終了時にタイムスタンプを取得しその名前で棋譜を保存する
  1. 棋譜を保存するか聞く
  2. 保存する場合recordディレクトリが存在するか確認し存在しなければ作る
  3. yyyyMMddHHmm.recordでファイルを作成し、@recordの中身を書き込む
#ゲームの進行
require "date"
require "fileutils"

...

def start_game

  ...

  save_record
end

#棋譜の保存
def save_record
  print("棋譜を保存しますか?(y/n)\n")
  ans = gets.chomp!
  if ans =~ /(y|n)/
    if ans == "y"
      #recordディレクトリがない場合作成する
      FileUtils.mkdir_p("record") unless FileTest.exist?("record")
      #現在時刻の取得
      time = DateTime.now.strftime('%Y%m%d%H%M')
      File.open("record/#{time}.record", "w") do |f|
        @record.each do |rec|
          f.puts(rec)
        end
      end
      print("#{time}.record で保存しました\n\n")
    end
  else
    print("yかnを入力してください\n")
    save_record
  end
end

3. 棋譜の読み込み

1. 読み込みモードの作成
  1. 読み込みモードを追加する
  2. 棋譜の一覧を表示する
  3. 選択された棋譜を読み込み配列に保存する
...

RECORD = 4
...

def menu
  while true
    ...
    if mode =~ /[1-4]/
      @mode = mode.to_i
      case @mode
      when COM
        ...
      when RECORD
        dir = Dir.glob("record/*.record") #棋譜の一覧の取得
        if dir.size == 0
          print("棋譜が存在しません\n\n")
          menu
        else
          print("棋譜一覧\n")
          dir.sort!
          dir.each_with_index do |name, i|
            print("#{i+1}: #{name}\n")
          end
          print("棋譜ファイル番号を入力してください:")
          num = gets.chomp!.to_i - 1
          file = dir[num]
          @read_record = [] #読み込んだ棋譜を保存する配列
          File.open(file) do |f|
            f.each_line do |line|
              @read_record.push(line)
            end
          end
        end
      end
      start_game
    else
      ...
    end
  end
end
2. 棋譜の再生
  1. 手番の棋譜を読み込む
  2. 石を打つ
  3. 読み込みモードの時は棋譜の保存をしない

手の表現のされ方は

  1. 人の指し手 = rowcol(a1~h8)
  2. comの指し手 = colrow(11~88)
  3. 棋譜 = rowcol(a1~h8)

put_stoneメソッドが受けつける表現は
`cell = [col, row]
1と3が同じ変換なのでメソッドに分割する

#ゲームの進行
def start_game
  ...
 
  if @mode != RECORD
    save_record
  end
end

def phase
  ...

  if turnable_cells.size == 0
    ...

  else
    ...

    case @mode
    when COM #COM戦の場合
      ...

    when HUMAN #対人戦の場合
      ...

    when WATCH #観戦の場合
      ...

    when RECORD #棋譜再生の場合
      read_record(@read_record[@turn])
    end
  end
end

def human(turnable_cells) #人が石を置く操作
  ...

  if move =~ /[a-h][1-8]/
    cell = cordinate_transformation(move) #座標の変換
    ...

  else
    ...

  end
end

def read_record(move) #棋譜の場合
  print(move)
  cell = cordinate_transformation(move)
  put_stone(cell, move)
end

#座標の変換
def cordinate_transformation(move)
  cell = move.split("")
  col = COL_NUM[cell[1]]
  row = ROW_NUM[cell[0]]
  cell = [col, row]
  return cell
end