2010年12月16日木曜日

棋譜のマージをするrubyライブラリ

「ライブラリ」と言えるほど高機能なものだろうか…。

とりあえず、Kifu for Windowsを複数起動したりしてコメントを見比べるのはナンセンス、ということで、コメントをマージするものを書いてみました。





kifu.rb:
require 'nkf'


module Kifu
  class Kifu
    attr_accessor :name


    CommentAreaStartingPattern = /^手数/
    CommentPattern = /^\*/


    def initialize string, name='' # must be UTF-8
      raise RuntimeError, "kif must be encoded with UTF8" if NKF.guess(string) != NKF::UTF8
      @kifu = string
      @name = name
    end


    def to_s
      @kifu
    end


    def to_s_with_name
      @kifu.gsub /^\*(.*)$/, "*#{@name}: \\1"
    end


    def to_s_with_name!
      @kifu.gsub! /^\*(.*)$/, "*#{@name}: \\1"
    end


    def comments
      result = Array.new
      comment = String.new
      comment_area = false
      comment_pattern = /^\*/


      @kifu.each_line do |line|
        comment_area = true if line.match CommentAreaStartingPattern
        if comment_area
          if line.match comment_pattern
            comment += line
          else
            result.push comment
            comment = ''
          end
        end
      end
      result.push comment
      return result[1..-1]
    end


    def comments_with_name
      comments.map{ |comment| comment.gsub /^\*(.*)$/, "*#{@name}: \\1" }
    end


    def merge kifu
      comments = Array.new
      comments_with_name2 = kifu.comments_with_name
      comments_with_name.each_with_index do |comment, index|
        comments.push(comment.to_s + comments_with_name2[index].to_s)
      end


      result = String.new
      comment_area = false
      tesuu = 0
      delete_comments_of_kifu_data(@kifu).each_line do |line|
        comment_area = true if line.match CommentAreaStartingPattern
        if not comment_area
          result += line
        else
          result += line
          result += comments[tesuu]
          tesuu += 1
        end
      end
      return Kifu.new(result)
    end


    def &(kifu)
      merge kifu
    end


    def delete_comments
      delete_comments_of_kifu_data @kifu
    end


    private
    def delete_comments_of_kifu_data data
      data.gsub(/^(\*.*)$/, "\n").gsub(/\n\n/, "")
    end


    def comment? string
      string.match CommentPattern
    end
  end
end


if $0 == __FILE__
  player1 = NKF.nkf("-w", File.read(ARGV[0]))
  player2 = NKF.nkf("-w", File.read(ARGV[1]))
  k1 = Kifu::Kifu.new player1, "将棋指しA"
  k2 = Kifu::Kifu.new player2, "将棋指しB"
  puts NKF.nkf("-s", (k1 & k2).to_s)
end

なんか思ったより長くなっちゃったなぁ…。 each とか正規表現多用で重い悪寒。汚いし。添削希望です><

とりあえず「同じ棋譜」に対して動作するように書かれていますので、違う棋譜を喰わせた場合にどうなるかは知りません。そのあたりはこれから RSpec でも書いて、必要に応じて対処していきます(順序が逆)。同一性チェックなので指し手だけで判断すればいいかなぁ。って、変化とか入れること考えたら今の実装じゃ対応できない。死ねる。

使い方は if $0 == __FILE__ から end までにある通りですが、 merge メソッド(エイリアス &)は新しい別の Kifu インスタンスを返すので、 kifu1 & kifu2 & another_kifu なんてことも可能ですきっと。


コマンドラインから呼び出す場合は


$ ruby kifu.rb kifuA.kif kifuB.kif


のようにしてください。もともとライブラリとしてしか使わない予定だったので3つ目以降の引数は無視されます。自分で拡張してください。もしくはパッチ投げてください。


その結果として、この間のあさねぼうさんとの棋譜をマージしてみました。以下。



#KIF version=2.0 encoding=Shift_JIS
# ---- Kifu for Windows V7 V7.00β4 棋譜ファイル ----
盤面回転
開始日時:2010/12/11 23:31:33
棋戦:レーティング対局室
手合割:平手  
先手:sandmark
後手:asanebou
手数----指手---------消費時間--
*あさねぼう: さんどさんと対戦だ!
*あさねぼう: 先手を取られてしまったので、たぶん中飛車でありましょう。
*さんどまーく: あさねぼうさんとの対局ぱーと2!
*さんどまーく: 先手番もらいました。ちなみに天下一将棋会ごっこも兼ねていたようです。
   1 5六歩(57)   ( 0:11/00:00:11)
   2 5四歩(53)   ( 0:22/00:00:22)
*あさねぼう: 中飛車対決を挑むことにしました。
*さんどまーく: 居飛車・四間飛車党のあさねぼうさんですが、最近は中飛車がマイブームだそうです。そしてこの位取り拒否。ということは…?
   3 5八飛(28)   ( 0:03/00:00:14)
*さんどまーく: この辺で「中飛車!有効!」などとチャット欄に打ち込んでは2人ではしゃいでいました。
   4 5二飛(82)   ( 0:03/00:00:25)
*さんどまーく: 相中飛車ー!
   5 7六歩(77)   ( 0:06/00:00:20)
   6 3四歩(33)   ( 0:09/00:00:34)
*さんどまーく: 「定跡!キャピーン!」(by あさねぼうさん
   7 4八玉(59)   ( 0:06/00:00:26)
   8 6二玉(51)   ( 0:17/00:00:51)
   9 3八玉(48)   ( 0:04/00:00:30)
  10 7二玉(62)   ( 0:07/00:00:58)
*あさねぼう: 中飛車にする→片美濃囲いをさっさと作る
*あさねぼう: →端歩を突いておく→攻撃開始が狙い
  11 9六歩(97)   ( 0:05/00:00:35)
*さんどまーく: 穴熊かどうかを打診する損のない手だと思っていましたが…
  12 9四歩(93)   ( 0:03/00:01:01)
  13 2八玉(38)   ( 0:02/00:00:37)
  14 8二玉(72)   ( 0:02/00:01:03)
  15 3八銀(39)   ( 0:03/00:00:40)
  16 7二銀(71)   ( 0:03/00:01:06)
  17 1六歩(17)   ( 0:01/00:00:41)
*あさねぼう: 94歩はいらない手と考え、指しませんでした。
  18 3二金(41)   ( 0:23/00:01:29)
*さんどまーく: 1筋の突き返しを手抜かれて先後逆転してしまいました。
  19 6六歩(67)   ( 0:02/00:00:43)
*あさねぼう: 角道を止めてくれたので
  20 3五歩(34)   ( 0:13/00:01:42)
*あさねぼう: 玉のコビンを開けに行きます。
*あさねぼう: すぐではなくても、将来的にとっておきます。
  21 6八銀(79)   ( 0:07/00:00:50)
  22 4二銀(31)   ( 0:05/00:01:47)
  23 5七銀(68)   ( 0:02/00:00:52)
  24 3三銀(42)   ( 0:07/00:01:54)
  25 4六銀(57)   ( 0:02/00:00:54)
*あさねぼう: せっかくの歩が取られそうなので
  26 4四銀(33)   ( 0:03/00:01:57)
*あさねぼう: ひもをつけておきます。
  27 6八金(69)   ( 0:08/00:01:02)
  28 6四歩(63)   ( 0:35/00:02:32)
*あさねぼう: 中飛車ではこの手が有効なようです。
*あさねぼう: 55角のラインから狙われる筋を消しておきます。
  29 6七金(68)   ( 0:02/00:01:04)
*あさねぼう: 55に効いている駒は
*あさねぼう: 
*あさねぼう: さんどさん3枚
*あさねぼう: 私は4枚
*さんどまーく: なんとか得意陣形に持っていきたい…
  30 5五歩(54)   ( 0:53/00:03:25)
*あさねぼう: 自信は無かったですが戦闘開始!
*さんどまーく: と思っていたら仕掛けが早かった。
  31 同 歩(56)   ( 0:19/00:01:23)
*さんどまーく: ▲同歩か▲同銀か迷いましたが、5筋の歩は切れていたほうがいいと判断したので▲同歩です。
*さんどまーく: いや、でも手抜くのもアリか…?
  32 同 銀(44)   ( 0:03/00:03:28)
  33 同 銀(46)   ( 0:06/00:01:29)
  34 同 角(22)   ( 0:07/00:03:35)
*さんどまーく: ここは△同飛と来られたら厄介だなと思っていました。選択肢がないので飛車を交換するしかなくなります。
  35 4一銀打     ( 0:04/00:01:33)
*あさねぼう: この割り打ちは予想していませんでした。
*あさねぼう: 56歩で角を追い払われると考えていました。
*さんどまーく: 割り打ちの銀。天下一将棋会2では「割り打ちの銀!」という音声も導入されるらしいです。
  36 5三飛(52)   ( 0:25/00:04:00)
*あさねぼう: 42飛だと55飛で角を取られます。
*あさねぼう: 
*あさねぼう: 51飛でも52歩とやられそうです。
*あさねぼう: 
*あさねぼう: 54飛だと金を取られた後に45金が痛いです。
*あさねぼう: 
*あさねぼう: しょうがなくここにしました。
  37 3二銀成(41) ( 0:05/00:01:38)
*あさねぼう: 金は取られてしまいましたが・・・
  38 3六歩(35)   ( 0:04/00:04:04)
*あさねぼう: 急所を攻めにかかります。
  39 4六金打     ( 1:15/00:02:53)
*あさねぼう: 堅実な受け!
*さんどまーく: 陣形は乱れますが、ここで角と金、飛車と飛車を交換しておけば楽になるかな?と思ったので角を殺しにかかりました。
*さんどまーく: が、よく考えたら△4六同角▲同歩△5八飛成▲同金の局面で△7八飛とかありましたね…。
*さんどまーく: とすると自然に▲4六同飛がよかったのかなぁ。
  40 3七歩成(36) ( 0:21/00:04:25)
*あさねぼう: とりあえず成りましょう。
  41 同 桂(29)   ( 0:04/00:02:57)
  42 3六歩打     ( 1:58/00:06:23)
*あさねぼう: 自信ない歩。
*あさねぼう: 
*あさねぼう: 55金なら37歩成→同銀→57歩→同飛→55桂を考えていました。
*あさねぼう: しかしあまり有効ではなさそうです。
  43 4五桂(37)   ( 0:09/00:03:06)
*あさねぼう: やはりここは55金が良かったと思います。
*あさねぼう: 
*あさねぼう: 37の地点が開き、駒が打てるようになりました。
*さんどまーく: ここは手抜いて▲5五金と出るべきでした。脊髄反射で跳ねてしまったんですよね…猛省。
*さんどまーく: おそらくこれが敗着でしょう。
  44 3七銀打     ( 0:07/00:06:30)
*あさねぼう: さっそくいきます
*さんどまーく: 嫌味をつけられました。
  45 同 銀(38)   ( 0:02/00:03:08)
  46 同 歩成(36) ( 0:04/00:06:34)
  47 同 玉(28)   ( 0:01/00:03:09)
  48 4六角(55)   ( 0:20/00:06:54)
*あさねぼう: 王手になるのが大きいですね。
*さんどまーく: これが王手になるのが辛い。
  49 同 歩(47)   ( 0:25/00:03:34)
  50 5八飛成(53) ( 0:06/00:07:00)
*あさねぼう: 飛車交換を挑んで
  51 同 金(49)   ( 0:02/00:03:36)
  52 3九飛打     ( 0:05/00:07:05)
*あさねぼう: さっそく王手にいきます。
*あさねぼう: 
*あさねぼう: 目標としては
*あさねぼう: 玉を右側に逃がさないことを考えていました。
  53 3八歩打     ( 0:41/00:04:17)
  54 4九飛成(39) ( 1:37/00:08:42)
*あさねぼう: なんとしても右側にやらせない手のつもり。
  55 4七金(58)   ( 0:57/00:05:14)
*さんどまーく: ▲4八金と龍に当てると、上から△3六銀などの送りの手筋があると思ったので、上部を警戒して4八に。
  56 3五歩打     ( 0:28/00:09:10)
*あさねぼう: しばっておきます。
  57 2五銀打     ( 0:52/00:06:06)
*あさねぼう: 36の地点を守る手ですが
*さんどまーく: 筋悪の受けですが…しのげば何とかなる!と思っての銀打ちです。
  58 2四歩(23)   ( 0:34/00:09:44)
*あさねぼう: どいてください、とお願いします。
*さんどまーく: 鮮やかに咎められました。
  59 4八金(47)   ( 2:06/00:08:12)
  60 3六銀打     ( 0:53/00:10:37)
  61 同 銀(25)   ( 0:04/00:08:16)
  62 同 歩(35)   ( 0:03/00:10:40)
  63 4七玉(37)   ( 0:05/00:08:21)
  64 5八銀打     ( 0:18/00:10:58)
*あさねぼう: 銀があってよかった!
*さんどまーく: もう先手陣は崩壊してます。
  65 3六玉(47)   ( 0:53/00:09:14)
*あさねぼう: あれ?まずいかもと思いました。
*あさねぼう: とりあえず将来に備えて金は取りましょう。
  66 4八龍(49)   ( 0:26/00:11:24)
  67 3五玉(36)   ( 0:02/00:09:16)
*あさねぼう: いかんいかんいかん!
  68 3八龍(48)   ( 0:44/00:12:08)
  69 2四玉(35)   ( 1:14/00:10:30)
*あさねぼう: 26歩がよかったかも知れません。
*あさねぼう: 44金と打ってどうなったかなー。
*さんどまーく: 何を思ったのか龍の利きを通してしまいました…。
*さんどまーく: とはいえ、▲3六歩と合駒したところで6七の金が質駒になっているので一手一手になりそうです。
  70 3二龍(38)   ( 0:11/00:12:19)
*あさねぼう: 銀を素抜いてもらっておきます。
  71 3三歩打     ( 0:22/00:10:52)
*あさねぼう: 今度は上部へ逃がさないようにしないと。
  72 2二龍(32)   ( 1:53/00:14:12)
*あさねぼう: 23歩が打てないのが痛いだろうなと思いました。
*さんどまーく: 歩が打てないのを突かれました…。完璧に歩で凌げると思い込んでました。リアルだったらこの時点で反則負けです。
  73 2三銀打     ( 0:11/00:11:03)
  74 1四金打     ( 0:13/00:14:25)
*あさねぼう: 銀合にはこの手がありました。
*あさねぼう: 
*あさねぼう: 本局はこの駒を使いたい!と思ったときに
*あさねぼう: きちんと持っていたのが大きかったです。
*さんどまーく: 1筋の歩を突き返されていないのがこんな形で響くとは…。
  75 3四玉(24)   ( 0:22/00:11:25)
*あさねぼう: 35玉ならまだ逃走できていたかも?
*さんどまーく: とにかく入玉したい気持ちで一杯で、「4三の歩を取ればああああ…!」とこんなところへ寄ってしまい、
  76 4四金打     ( 0:23/00:14:48)
*あさねぼう: これは1手詰みですね。
*さんどまーく: 即死。
*さんどまーく: いや、▲3五玉でも一手一手で勝てる見込みはありませんね。
*さんどまーく: さすがにお強い…。
*さんどまーく: あさねぼうさん、対局ありがとうございました!
  77 投了         ( 0:00/00:11:25)
*あさねぼう: これで投了となりました。
*あさねぼう: 
*あさねぼう: 本局は43手目の45桂が、さんどさんの悪手であったと思います。
*あさねぼう: あそこで55金と角を取られていたら、おそらくこちらの負けでした。
*あさねぼう: 
*あさねぼう: 幸運があり、勝負に勝つことができました。
*あさねぼう: さんどさんありがとうございました!
*あさねぼう: 
*あさねぼう: また対戦しましょうね!
まで76手で後手の勝ち


押してねっ→BlogPeople「趣味の世界」ブログランキング

0 件のコメント:

コメントを投稿