lib/jkf/parser/kif.rb in jkf-0.4.0 vs lib/jkf/parser/kif.rb in jkf-0.4.1

- old
+ new

@@ -1,159 +1,75 @@ # coding: utf-8 module Jkf::Parser class Kif < Base + include Kifuable + def parse_root - @input += "\n" if @input[-1] != "\n" + @input += "\n" unless @input.end_with?("\n") + s0 = @current_pos s1 = [] s2 = parse_skipline while s2 != :failed s1 << s2 s2 = parse_skipline end - if s1 != :failed - s2 = [] + + s2 = [] + s3 = parse_header + while s3 != :failed + s2 << s3 s3 = parse_header - while s3 != :failed - s2 << s3 - s3 = parse_header + end + s3 = parse_initialboard + s3 = nil if s3 == :failed + s4 = [] + s5 = parse_header + while s5 != :failed + s4 << s5 + s5 = parse_header + end + parse_split + s6 = parse_moves + if s6 != :failed + s7 = [] + s8 = parse_fork + while s8 != :failed + s7 << s8 + s8 = parse_fork end - if s2 != :failed - s3 = parse_initial_board - s3 = nil if s3 == :failed - if s3 != :failed - s4 = [] - s5 = parse_header - while s5 != :failed - s4 << s5 - s5 = parse_header - end - if s4 != :failed - s5 = parse_split - s5 = nil if s5 == :failed - if s5 != :failed - s6 = parse_moves - if s6 != :failed - s7 = [] - s8 = parse_fork - while s8 != :failed - s7 << s8 - s8 = parse_fork - end - if s7 != :failed - s8 = parse_nl - s8 = nil if s8 == :failed - if s8 != :failed - @reported_pos = s0 - s1 = -> (headers, ini, headers2, moves, forks) { - ret = { "header" => {}, "moves" => moves } - headers.compact.each { |h| ret["header"][h["k"]] = h["v"] } - headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] } - if ini - ret["initial"] = ini - elsif ret["header"]["手合割"] - preset = preset2str(ret["header"]["手合割"]) - ret["initial"] = { "preset" => preset } if preset && preset != "OTHER" - end - if ret["initial"] && ret["initial"]["data"] - if ret["header"]["手番"] - ret["initial"]["data"]["color"] = ("下先".include?(ret["header"]["手番"]) ? 0 : 1) - ret["header"].delete("手番") - else - ret["initial"]["data"]["color"] = 0 - end - ret["initial"]["data"]["hands"] = [ - make_hand(ret["header"]["先手の持駒"] || ret["header"]["下手の持駒"]), - make_hand(ret["header"]["後手の持駒"] || ret["header"]["上手の持駒"]) - ] - %w(先手の持駒 下手の持駒 後手の持駒 上手の持駒).each do |key| - ret["header"].delete(key) - end - end - fork_stack = [{ "te" => 0, "moves" => moves }] - forks.each do |f| - now_fork = f - _fork = fork_stack.pop - _fork = fork_stack.pop while _fork["te"] > now_fork["te"] - move = _fork["moves"][now_fork["te"] - _fork["te"]] - move["forks"] ||= [] - move["forks"] << now_fork["moves"] - fork_stack << _fork - fork_stack << now_fork - end - reverse_color(ret['moves']) if ret["initial"] && ret["initial"]["data"] && ret["initial"]["data"]["color"] == 1 - ret - }.call(s2, s3, s4, s6, s7) - s0 = s1 - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end + parse_nl + @reported_pos = s0 + s0 = transform_root(s2, s3, s4, s6, s7) else @current_pos = s0 s0 = :failed end s0 end def parse_header s0 = @current_pos - s1 = [] s2 = match_regexp(/^[^:\r\n]/) if s2 != :failed + s1 = [] while s2 != :failed s1 << s2 s2 = match_regexp(/^[^:\r\n]/) end else s1 = :failed end if s1 != :failed - s2 = match_str(":") - if s2 != :failed - s3 = [] - s4 = parse_nonl - while s4 != :failed - s3 << s4 - s4 = parse_nonl - end - if s3 != :failed - s4 = parse_nl - if s4 != :failed - @reported_pos = s0 - s1 = { "k" => s1.join, "v" => s3.join } - s0 = s1 - else - @current_pos = s0 - s0 = :failed - end + if match_str(":") != :failed + s3 = parse_nonls + if parse_nl != :failed + @reported_pos = s0 + s1 = { "k" => s1.join, "v" => s3.join } + s0 = s1 else @current_pos = s0 s0 = :failed end else @@ -166,16 +82,14 @@ end if s0 == :failed s0 = @current_pos s1 = parse_turn if s1 != :failed - s2 = match_str("手番") - if s2 != :failed - s3 = parse_nl - if s3 != :failed + if match_str("手番") != :failed + if parse_nl != :failed @reported_pos = s0 - s0 = s1 = { "k" => "手番", "v" => s1 } + s0 = { "k" => "手番", "v" => s1 } else @current_pos = s0 s0 = :failed end else @@ -186,16 +100,14 @@ @current_pos = s0 s0 = :failed end if s0 == :failed s0 = @current_pos - s1 = match_str("盤面回転") - if s1 != :failed - s2 = parse_nl - if s2 != :failed + if match_str("盤面回転") != :failed + if parse_nl != :failed @reported_pos = s0 - s0 = s1 = nil + s0 = nil else @current_pos = s0 s0 = :failed end else @@ -210,262 +122,19 @@ def parse_turn match_regexp(/[先後上下]/) end - def parse_initial_board - s0 = s1 = @current_pos - s2 = match_str(" ") - if s2 != :failed - s3 = [] - s4 = parse_nonl - while s4 != :failed - s3 << s4 - s4 = parse_nonl - end - if s3 != :failed - s4 = parse_nl - if s4 != :failed - s1 = s2 = [s2, s3, s4] - else - @current_pos = s1 - s1 = :failed - end - else - @current_pos = s1 - s1 = :failed - end - else - @current_pos = s1 - s1 = :failed - end - if s1 == :failed - s1 = nil - end - if s1 != :failed - s2 = @current_pos - s3 = match_str("+") - if s3 != :failed - s4 = [] - s5 = parse_nonl - while s5 != :failed - s4 << s5 - s5 = parse_nonl - end - if s4 != :failed - s5 = parse_nl - if s5 != :failed - s2 = s3 = [s3, s4, s5] - else - @current_pos = s2 - s2 = :failed - end - else - @current_pos = s2 - s2 = :failed - end - else - @current_pos = s2 - s2 = :failed - end - s2 = nil if s2 == :failed - if s2 != :failed - s3 = [] - s4 = parse_ikkatsu_line - if s4 != :failed - while s4 != :failed - s3 << s4 - s4 = parse_ikkatsu_line - end - else - s3 = :failed - end - if s3 != :failed - s4 = @current_pos - s5 = match_str("+") - if s5 != :failed - s6 = [] - s7 = parse_nonl - while s7 != :failed - s6 << s7 - s7 = parse_nonl - end - if s6 != :failed - s7 = parse_nl - if s7 != :failed - s4 = s5 = [s5, s6, s7] - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - s4 = nil if s4 == :failed - if s4 != :failed - @reported_pos = s0 - s1 = -> (lines) { - ret = []; - 9.times { |i| - line = []; - 9.times { |j| - line << lines[j][8-i] - } - ret << line - } - { "preset" => "OTHER", "data" => { "board" => ret } } - }.call(s3) - s0 = s1 - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - - s0 - end - - def parse_ikkatsu_line - s0 = @current_pos - s1 = match_str("|") - if s1 != :failed - s2 = [] - s3 = parse_masu - if s3 != :failed - while s3 != :failed - s2 << s3 - s3 = parse_masu - end - else - s2 = :failed - end - if s2 != :failed - s3 = match_str("|") - if s3 != :failed - s4 = [] - s5 = parse_nonl - if s5 != :failed - while s5 != :failed - s4 << s5 - s5 = parse_nonl - end - else - s4 = :failed - end - if s4 != :failed - s5 = parse_nl - if s5 != :failed - @reported_pos = s0 - s0 = s1 = s2 - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - - s0 - end - - def parse_masu - s0 = @current_pos - s1 = parse_teban - if s1 != :failed - s2 = parse_piece - if s2 != :failed - @reported_pos = s0 - s0 = s1 = { "color" => s1, "kind" => s2 } - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - if s0 == :failed - s0 = @current_pos - s1 = match_str(" ・") - if s1 != :failed - @reported_pos = s0 - s1 = {} - end - s0 = s1 - end - - s0 - end - - def parse_teban - s0 = @current_pos - s1 = match_str(" ") - if s1 == :failed - s1 = match_str("+") - s1 = match_str("^") if s1 == :failed - end - if s1 != :failed - @reported_pos = s0 - s1 = 0 - end - s0 = s1 - if s0 == :failed - s0 = @current_pos - s1 = match_str("v") - s1 = match_str("V") if s1 == :failed - if s1 != :failed - @reported_pos = s0 - s1 = 1 - end - s0 = s1 - end - s0 - end - def parse_split s0 = @current_pos s1 = match_str("手数----指手--") if s1 != :failed s2 = match_str("-------消費時間--") s2 = nil if s2 == :failed - if s2 != :failed - s3 = parse_nl - if s3 != :failed - s0 = s1 = [s1, s2, s3] - else - @current_pos = s0 - s0 = :failed - end + s3 = parse_nl + if s3 != :failed + s0 = [s1, s2, s3] else @current_pos = s0 s0 = :failed end else @@ -477,37 +146,20 @@ def parse_moves s0 = @current_pos s1 = parse_firstboard if s1 != :failed - s2 = parse_split - s2 = nil if s2 == :failed - if s2 != :failed - s3 = [] - s4 = parse_move - while s4 != :failed - s3 << s4 - s4 = parse_move - end - if s3 != :failed - s4 = parse_result - s4 = nil if s4 == :failed - if s4 != :failed - @reported_pos = s0 - s0 = s1 = s3.unshift(s1) - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed + parse_split + s2 = [] + s3 = parse_move + while s3 != :failed + s2 << s3 + s3 = parse_move end + parse_result + @reported_pos = s0 + s0 = s2.unshift(s1) else @current_pos = s0 s0 = :failed end s0 @@ -519,26 +171,13 @@ s2 = parse_comment while s2 != :failed s1 << s2 s2 = parse_comment end - if s1 != :failed - s2 = parse_pointer - if s2 == :failed - s2 = nil - end - if s2 != :failed - @reported_pos = s0 - s0 = s1 = s1.length == 0 ? {} : { "comments" => s1 } - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end + parse_pointer + @reported_pos = s0 + s0 = s1.empty? ? {} : { "comments" => s1 } s0 end def parse_move s0 = @current_pos @@ -548,164 +187,60 @@ s3 = parse_comment while s3 != :failed s2 << s3 s3 = parse_comment end - if s2 != :failed - s3 = parse_pointer - s3 = nil if s3 == :failed - if s3 != :failed - @reported_pos = s0 - s1 = -> (line, c) { - ret = {} - ret["comments"] = c if c.length > 0 - if line["move"].is_a? Hash - ret["move"] = line["move"] - else - ret["special"] = special2csa(line["move"]) - end - ret["time"] = line["time"] if line["time"] - ret - }.call(s1, s2) - s0 = s1 - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end + parse_pointer + @reported_pos = s0 + s0 = transform_move(s1, s2) else @current_pos = s0 s0 = :failed end s0 end - def parse_pointer + def parse_line s0 = @current_pos - s1 = match_str("&") - if s1 != :failed - s2 = [] - s3 = parse_nonl - while s3 != :failed - s2 << s3 - s3 = parse_nonl - end - if s2 != :failed - s3 = parse_nl - if s3 != :failed - s0 = s1 = [s1, s2, s3] + match_spaces + s2 = parse_te + if s2 != :failed + match_spaces + s4 = @current_pos + s5 = parse_fugou + if s5 != :failed + s6 = parse_from + if s6 != :failed + @reported_pos = s4 + s4 = transform_teban_fugou_from(s2, s5, s6) else - @current_pos = s0 - s0 = :failed + @current_pos = s4 + s4 = :failed end else - @current_pos = s0 - s0 = :failed + @current_pos = s4 + s4 = :failed end - else - @current_pos = s0 - s0 = :failed - end - s0 - end - - def parse_line - s0 = @current_pos - s1 = [] - s2 = match_str(" ") - while s2 != :failed - s1 << s2 - s2 = match_str(" ") - end - if s1 != :failed - s2 = parse_te - if s2 != :failed - s3 = [] - s4 = match_str(" ") - while s4 != :failed - s3 << s4 - s4 = match_str(" ") + if s4 == :failed + s4 = @current_pos + s5 = [] + s6 = match_regexp(/^[^\r\n ]/) + while s6 != :failed + s5 << s6 + s6 = match_regexp(/^[^\r\n ]/) end - if s3 != :failed - s4 = @current_pos - s5 = parse_fugou - if s5 != :failed - s6 = parse_from - if s6 != :failed - @reported_pos = s4 - s5 = -> (teban, fugou, from) { - ret = { "color" => teban2color(teban.join), "piece" => fugou["piece"] } - if fugou["to"] - ret["to"] = fugou["to"] - else - ret["same"] = true - end - ret["promote"] = true if fugou["promote"] - ret["from"] = from if from - ret - }.call(s2, s5, s6) - s4 = s5 - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - if s4 == :failed - s4 = @current_pos - s5 = [] - s6 = match_regexp(/^[^\r\n ]/) - while s6 != :failed - s5 << s6 - s6 = match_regexp(/^[^\r\n ]/) - end - @reported_pos = s4 - s4 = s5 = s5.join - end - if s4 != :failed - s5 = [] - s6 = match_str(" ") - while s6 != :failed - s5 << s6 - s6 = match_str(" ") - end - if s5 != :failed - s6 = parse_time - s6 = nil if s6 == :failed - if s6 != :failed - s7 = match_str("+") - s7 = nil if s7 == :failed - if s7 != :failed - s8 = parse_nl - if s8 != :failed - @reported_pos = s0 - s0 = s1 = { "move" => s4, "time" => s6 } - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end + @reported_pos = s4 + s4 = s5.join + end + if s4 != :failed + match_spaces + s6 = parse_time + s6 = nil if s6 == :failed + match_str("+") + if parse_nl != :failed + @reported_pos = s0 + s0 = { "move" => s4, "time" => s6 } else @current_pos = s0 s0 = :failed end else @@ -718,38 +253,23 @@ end s0 end def parse_te - s0 = [] - s1 = match_regexp(/^[0-9]/) - if s1 != :failed - while s1 != :failed - s0 << s1 - s1 = match_regexp(/^[0-9]/) - end - else - s0 = :failed - end - s0 + match_digits! end def parse_fugou s0 = @current_pos s1 = parse_place if s1 != :failed s2 = parse_piece if s2 != :failed s3 = match_str("成") s3 = nil if s3 == :failed - if s3 != :failed - @reported_pos = s0 - s0 = s1 = { "to" => s1, "piece" => s2, "promote" => !!s3 } - else - @current_pos = s0 - s0 = :failed - end + @reported_pos = s0 + s0 = { "to" => s1, "piece" => s2, "promote" => !!s3 } else @current_pos = s0 s0 = :failed end else @@ -764,11 +284,11 @@ s1 = parse_num if s1 != :failed s2 = parse_numkan if s2 != :failed @reported_pos = s0 - s0 = s1 = { "x" => s1, "y" => s2 } + s0 = { "x" => s1, "y" => s2 } else @current_pos = s0 s0 = :failed end else @@ -785,70 +305,28 @@ s0 = s1 end s0 end - def parse_num - s0 = @current_pos - s1 = match_regexp(/^[123456789]/) - if s1 != :failed - @reported_pos = s0 - s1 = zen2n(s1) - end - s1 - end - - def parse_numkan - s0 = @current_pos - s1 = match_regexp(/^[一二三四五六七八九]/) - if s1 != :failed - @reported_pos = s0 - s1 = kan2n(s1) - end - s1 - end - - def parse_piece - s0 = @current_pos - s1 = match_str("成") - s1 = "" if s1 == :failed - if s1 != :failed - s2 = match_regexp(/^[歩香桂銀金角飛王玉と杏圭全馬竜龍]/) - if s2 != :failed - @reported_pos = s0 - s0 = s1 = kind2csa(s1+s2) - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - s0 - end - def parse_from s0 = @current_pos s1 = match_str("打") if s1 != :failed @reported_pos = s0 s1 = nil end s0 = s1 if s0 == :failed s0 = @current_pos - s1 = match_str("(") - if s1 != :failed + if match_str("(") != :failed s2 = match_regexp(/^[1-9]/) if s2 != :failed s3 = match_regexp(/^[1-9]/) if s3 != :failed - s4 = match_str(")") - if s4 != :failed + if match_str(")") != :failed @reported_pos = s0 - s0 = s1 = { "x" => s2.to_i, "y" => s3.to_i } + s0 = { "x" => s2.to_i, "y" => s3.to_i } else @current_pos = s0 s0 = :failed end else @@ -867,34 +345,21 @@ s0 end def parse_time s0 = @current_pos - s1 = match_str("(") - if s1 != :failed - s2 = [] - s3 = match_str(" ") - while s3 != :failed - s2 << s3 - s3 = match_str(" ") - end - if s2 != :failed - s3 = parse_ms - if s3 != :failed - s4 = match_str("/") - if s4 != :failed - s5 = parse_hms - s5 = parse_ms(with_hour: true) if s5 == :failed - if s5 != :failed - s6 = match_str(")") - if s6 != :failed - @reported_pos = s0 - s0 = s1 = { "now" => s3, "total" => s5 } - else - @current_pos = s0 - s0 = :failed - end + if match_str("(") != :failed + match_spaces + s3 = parse_ms + if s3 != :failed + if match_str("/") != :failed + s5 = parse_hms + s5 = parse_ms(with_hour: true) if s5 == :failed + if s5 != :failed + if match_str(")") != :failed + @reported_pos = s0 + s0 = { "now" => s3, "total" => s5 } else @current_pos = s0 s0 = :failed end else @@ -916,50 +381,21 @@ s0 end def parse_hms s0 = @current_pos - s1 = [] - s2 = match_regexp(/^[0-9]/) - if s2 != :failed - while s2 != :failed - s1 << s2 - s2 = match_regexp(/^[0-9]/) - end - else - s1 = :failed - end + s1 = match_digits! if s1 != :failed - s2 = match_str(":") - if s2 != :failed - s3 = [] - s4 = match_regexp(/^[0-9]/) - if s4 != :failed - while s4 != :failed - s3 << s4 - s4 = match_regexp(/^[0-9]/) - end - else - s3 = :failed - end + if match_str(":") != :failed + s3 = match_digits! if s3 != :failed - s4 = match_str(":") - if s4 != :failed - s5 = [] - s6 = match_regexp(/^[0-9]/) - if s6 != :failed - while s6 != :failed - s5 << s6 - s6 = match_regexp(/^[0-9]/) - end - else - s5 = :failed - end + if match_str(":") != :failed + s5 = match_digits! if s5 != :failed @reported_pos = s0 - s0 = s1 = { "h" => s1.join.to_i, "m" => s3.join.to_i, "s" => s5.join.to_i } + s0 = { "h" => s1.join.to_i, "m" => s3.join.to_i, "s" => s5.join.to_i } else @current_pos = s0 s0 = :failed end else @@ -981,43 +417,24 @@ s0 end def parse_ms(with_hour: false) s0 = @current_pos - s1 = [] - s2 = match_regexp(/^[0-9]/) - if s2 != :failed - while s2 != :failed - s1 << s2 - s2 = match_regexp(/^[0-9]/) - end - else - s1 = :failed - end + s1 = match_digits! if s1 != :failed - s2 = match_str(":") - if s2 != :failed - s3 = [] - s4 = match_regexp(/^[0-9]/) - if s4 != :failed - while s4 != :failed - s3 << s4 - s4 = match_regexp(/^[0-9]/) - end - else - s3 = :failed - end + if match_str(":") != :failed + s3 = match_digits! if s3 != :failed @reported_pos = s0 m = s1.join.to_i s = s3.join.to_i if with_hour h = m / 60 m = m % 60 - s0 = s1 = { "h" => h, "m" => m, "s" => s } + s0 = { "h" => h, "m" => m, "s" => s } else - s0 = s1 = { "m" => m, "s" => s } + s0 = { "m" => m, "s" => s } end else @current_pos = s0 s0 = :failed end @@ -1032,28 +449,15 @@ s0 end def parse_comment s0 = @current_pos - s1 = match_str("*") - if s1 != :failed - s2 = [] - s3 = parse_nonl - while s3 != :failed - s2 << s3 - s3 = parse_nonl - end - if s2 != :failed - s3 = parse_nl - if s3 != :failed - @reported_pos = s0 - s1 = s2.join - s0 = s1 - else - @current_pos = s0 - s0 = :failed - end + if match_str("*") != :failed + s2 = parse_nonls + if parse_nl != :failed + @reported_pos = s0 + s0 = s2.join else @current_pos = s0 s0 = :failed end else @@ -1062,26 +466,14 @@ end if s0 == :failed s0 = @current_pos s1 = match_str("&") if s1 != :failed - s2 = [] - s3 = parse_nonl - while s3 != :failed - s2 << s3 - s3 = parse_nonl - end - - if s2 != :failed - s3 = parse_nl - if s3 != :failed - @reported_pos = s0 - s0 = s1 = "&" + s2.join - else - @current_pos = s0 - s0 = :failed - end + s2 = parse_nonls + if parse_nl != :failed + @reported_pos = s0 + s0 = "&" + s2.join else @current_pos = s0 s0 = :failed end else @@ -1090,182 +482,22 @@ end end s0 end - def parse_result + def parse_fork s0 = @current_pos - s1 = match_str("まで") - - if s1 != :failed - s2 = [] - s3 = match_regexp(/^[0-9]/) + if match_str("変化:") != :failed + match_spaces + s3 = parse_te if s3 != :failed - while s3 != :failed - s2 << s3 - s3 = match_regexp(/^[0-9]/) - end - else - s2 = :failed - end - if s2 != :failed - s3 = match_str("手") - if s3 != :failed - s4 = @current_pos - s5 = match_str("で") - if s5 != :failed - s6 = parse_turn + if match_str("手") != :failed + if parse_nl != :failed + s6 = parse_moves if s6 != :failed - s7 = match_str("手の") - if s7 != :failed - s8 = @current_pos - s9 = match_str("勝ち") - if s9 != :failed - @reported_pos = s8 - s9 = "TORYO" - end - s8 = s9 - if s8 == :failed - s8 = @current_pos - s9 = match_str("反則") - if s9 != :failed - s10 = @current_pos - s11 = match_str("勝ち") - if s11 != :failed - @reported_pos = s10 - s11 = "ILLEGAL_ACTION" - end - s10 = s11 - if s10 == :failed - s10 = @current_pos - s11 = match_str("負け") - if s11 != :failed - @reported_pos = s10 - s11 = "ILLEGAL_MOVE" - end - s10 = s11 - end - if s10 != :failed - @reported_pos = s8 - s8 = s9 = s10 - else - @current_pos = s8 - s8 = :failed - end - else - @current_pos = s8 - s8 = :failed - end - end - if s8 != :failed - @reported_pos = s4 - s4 = s5 = s8 - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - if s4 == :failed - s4 = @current_pos - s5 = match_str("で時間切れにより") - if s5 != :failed - s6 = parse_turn - if s6 != :failed - s7 = match_str("手の勝ち") - if s7 != :failed - @reported_pos = s4 - s4 = s5 = "TIME_UP" - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - if s4 == :failed - s4 = @current_pos - s5 = match_str("で中断") - if s5 != :failed - @reported_pos = s4 - s5 = "CHUDAN" - end - s4 = s5 - if s4 == :failed - s4 = @current_pos - s5 = match_str("で持将棋") - if s5 != :failed - @reported_pos = s4 - s5 = "JISHOGI" - end - s4 = s5 - if s4 == :failed - s4 = @current_pos - s5 = match_str("で千日手") - if s5 != :failed - @reported_pos = s4 - s5 = "SENNICHITE" - end - s4 = s5 - if s4 == :failed - s4 = @current_pos - s5 = match_str("で") - s5 = nil if s5 == :failed - if s5 != :failed - s6 = match_str("詰") - if s6 != :failed - s7 = match_str("み") - s7 = nil if s7 == :failed - if s7 != :failed - @reported_pos = s4 - s4 = s5 = "TSUMI" - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - else - @current_pos = s4 - s4 = :failed - end - if s4 == :failed - s4 = @current_pos - s5 = match_str("で不詰") - if s5 != :failed - @reported_pos = s4 - s5 = "FUZUMI" - end - s4 = s5 - end - end - end - end - end - end - if s4 != :failed - s5 = parse_nl - if s5 != :failed @reported_pos = s0 - s0 = s1 = s4 + s0 = { "te" => s3.join.to_i, "moves" => s6[1..-1] } else @current_pos = s0 s0 = :failed end else @@ -1285,218 +517,54 @@ s0 = :failed end s0 end - def parse_fork - s0 = @current_pos - s1 = match_str("変化:") - if s1 != :failed - s2 = [] - s3 = match_str(" ") - while s3 != :failed - s2 << s3 - s3 = match_str(" ") - end - if s2 != :failed - s3 = parse_te - if s3 != :failed - s4 = match_str("手") - if s4 != :failed - s5 = parse_nl - if s5 != :failed - s6 = parse_moves - if s6 != :failed - @reported_pos = s0 - s0 = s1 = { "te" => s3.join.to_i, "moves" => s6[1..-1] } - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end - s0 - end + protected - def parse_nl - s0 = @current_pos - s1 = [] - s2 = parse_newline - if s2 != :failed - while (s2 != :failed) - s1 << s2 - s2 = parse_newline - end - else - s1 = :failed + def transform_root(headers, ini, headers2, moves, forks) + ret = { "header" => {}, "moves" => moves } + headers.compact.each { |h| ret["header"][h["k"]] = h["v"] } + headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] } + if ini + ret["initial"] = ini + elsif ret["header"]["手合割"] + preset = preset2str(ret["header"]["手合割"]) + ret["initial"] = { "preset" => preset } if preset && preset != "OTHER" end - if s1 != :failed - s2 = [] - s3 = parse_skipline - while s3 != :failed - s2 << s3 - s3 = parse_skipline - end - if s2 != :failed - s0 = s1 = [s1, s2] - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed + transform_root_header_data(ret) if ret["initial"] && ret["initial"]["data"] + transform_root_forks(forks, moves) + if ret["initial"] && ret["initial"]["data"] && ret["initial"]["data"]["color"] == 1 + reverse_color(ret["moves"]) end - - s0 + ret end - def parse_skipline - s0 = @current_pos - s1 = match_str("#") - if s1 != :failed - s2 = [] - s3 = parse_nonl - while s3 != :failed - s2 << s3 - s3 = parse_nonl - end - if s2 != :failed - s3 = parse_newline - if s3 != :failed - s0 = s1 = [s1, s2, s3] - else - @current_pos = s0 - s0 = :failed - end - else - @current_pos = s0 - s0 = :failed - end + def transform_move(line, c) + ret = {} + ret["comments"] = c if !c.empty? + if line["move"].is_a? Hash + ret["move"] = line["move"] else - @current_pos = s0 - s0 = :failed + ret["special"] = special2csa(line["move"]) end - s0 + ret["time"] = line["time"] if line["time"] + ret end - def parse_whitespace - match_regexp(/^[ \t]/) - end - - def parse_newline - s0 = @current_pos - s1 = [] - s2 = parse_whitespace - while s2 != :failed - s1 << s2 - s2 = parse_whitespace - end - if s1 != :failed - s2 = match_str("\n") - if s2 == :failed - s2 = @current_pos - s3 = match_str("\r") - if s3 != :failed - s4 = match_str("\n") - s4 = nil if s4 == :failed - if s4 != :failed - s2 = s3 = [s3, s4] - else - @current_pos = s2 - s2 = :failed - end - else - @current_pos = s2 - s2 = :failed - end - end - if s2 != :failed - s0 = s1 = [s1, s2] - else - @current_pos = s0 - s0 = :failed - end + def transform_teban_fugou_from(teban, fugou, from) + ret = { "color" => teban2color(teban.join), "piece" => fugou["piece"] } + if fugou["to"] + ret["to"] = fugou["to"] else - @current_pos = s0 - s0 = :failed + ret["same"] = true end - s0 + ret["promote"] = true if fugou["promote"] + ret["from"] = from if from + ret end - def parse_nonl - match_regexp(/^[^\r\n]/) - end - - protected - - def zen2n(s) - "0123456789".index(s) - end - - def kan2n(s) - "〇一二三四五六七八九".index(s) - end - - def kan2n2(s) - case s.length - when 1 - "〇一二三四五六七八九十".index(s) - when 2 - "〇一二三四五六七八九十".index(s[1])+10 - else - raise "21以上の数値に対応していません" - end - end - - def kind2csa(kind) - if kind[0] == "成" - { - "香" => "NY", - "桂" => "NK", - "銀" => "NG" - }[kind[1]] - else - { - "歩" => "FU", - "香" => "KY", - "桂" => "KE", - "銀" => "GI", - "金" => "KI", - "角" => "KA", - "飛" => "HI", - "玉" => "OU", - "王" => "OU", - "と" => "TO", - "杏" => "NY", - "圭" => "NK", - "全" => "NG", - "馬" => "UM", - "竜" => "RY", - "龍" => "RY" - }[kind] - end - end - def special2csa(str) { "中断" => "CHUDAN", "投了" => "TORYO", "持将棋" => "JISHOGI", @@ -1507,52 +575,33 @@ "反則勝ち" => "ILLEGAL_ACTION", # 直前の手が反則(先頭に+か-で反則した側の情報を含める必要が有る) "反則負け" => "ILLEGAL_MOVE" # ここで手番側が反則,反則の内容はコメントで表現 }[str] || (raise ParseError) end - def preset2str(preset) - { - "平手" => "HIRATE", - "香落ち" => "KY", - "右香落ち" => "KY_R", - "角落ち" => "KA", - "飛車落ち" => "HI", - "飛香落ち" => "HIKY", - "二枚落ち" => "2", - "三枚落ち" => "3", - "四枚落ち" => "4", - "五枚落ち" => "5", - "左五枚落ち" => "5_L", - "六枚落ち" => "6", - "八枚落ち" => "8", - "十枚落ち" => "10", - "その他" => "OTHER", - }[preset.gsub(/\s/, "")] - end - def teban2color(teban) teban = teban.to_i unless teban.is_a? Fixnum - (teban+1) % 2 + (teban + 1) % 2 end def make_hand(str) # Kifu for iPhoneは半角スペース区切り - kinds = str.split(/[  ]/) ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 } return ret if str.empty? - kinds.each do |kind| + str.split(/[  ]/).each do |kind| next if kind.empty? ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1]) end ret end def reverse_color(moves) moves.each do |move| - move['move']['color'] = (move['move']['color'] + 1) % 2 if move['move'] && move['move']['color'] - move['forks'].each { |_fork| reverse_color(_fork) } if move['forks'] + if move["move"] && move["move"]["color"] + move["move"]["color"] = (move["move"]["color"] + 1) % 2 + end + move["forks"].each { |_fork| reverse_color(_fork) } if move["forks"] end end end end