lib/jkf/parser/ki2.rb in jkf-0.5.0 vs lib/jkf/parser/ki2.rb in jkf-0.5.1

- old
+ new

@@ -1,422 +1,420 @@ -# coding: utf-8 +module Jkf + module Parser + # KI2 Parser + class Ki2 < Base + include Kifuable -module Jkf::Parser - # KI2 Parser - class Ki2 < Base - include Kifuable + protected - protected - - # kifu : header* initialboard? header* moves fork* - def parse_root - s0 = @current_pos - s1 = [] - s2 = parse_header - while s2 != :failed - s1 << s2 + # kifu : header* initialboard? header* moves fork* + def parse_root + s0 = @scanner.pos + s1 = [] s2 = parse_header - end - if s1 == :failed - @current_pos = s0 - s0 = :failed - else - s2 = parse_initialboard - s2 = nil if s2 == :failed - s3 = [] - s4 = parse_header - while s4 != :failed - s3 << s4 - s4 = parse_header + while s2 != :failed + s1 << s2 + s2 = parse_header end - s4 = parse_moves - if s4 == :failed - @current_pos = s0 + if s1 == :failed + @scanner.pos = s0 s0 = :failed else - s5 = [] - s6 = parse_fork - while s6 != :failed - s5 << s6 + s2 = parse_initialboard + s2 = nil if s2 == :failed + s3 = [] + s4 = parse_header + while s4 != :failed + s3 << s4 + s4 = parse_header + end + s4 = parse_moves + if s4 == :failed + @scanner.pos = s0 + s0 = :failed + else + s5 = [] s6 = parse_fork + while s6 != :failed + s5 << s6 + s6 = parse_fork + end + @reported_pos = s0 + s0 = transform_root(s1, s2, s3, s4, s5) end - @reported_pos = s0 - s0 = transform_root(s1, s2, s3, s4, s5) end + s0 end - s0 - end - # header : [^:\r\n]+ ":" nonls nl+ | header_teban - def parse_header - s0 = @current_pos - s2 = match_regexp(/^[^*:\r\n]/) - if s2 == :failed - s1 = :failed - else - s1 = [] - while s2 != :failed - s1 << s2 - s2 = match_regexp(/^[^:\r\n]/) - end - end - if s1 == :failed - @current_pos = s0 - s0 = :failed - elsif match_str(":") != :failed - s3 = parse_nonls - s5 = parse_nl - if s5 == :failed - s4 = :failed + # header : [^:\r\n]+ ":" nonls nl+ | header_teban + def parse_header + s0 = @scanner.pos + s2 = match_regexp(/[^*:\r\n]/) + if s2 == :failed + s1 = :failed else - s4 = [] - while s5 != :failed - s4 << s5 - s5 = parse_nl + s1 = [] + while s2 != :failed + s1 << s2 + s2 = match_regexp(/[^:\r\n]/) end end - if s4 == :failed - @current_pos = s0 + if s1 == :failed + @scanner.pos = s0 s0 = :failed + elsif match_str(':') != :failed + s3 = parse_nonls + s5 = parse_nl + if s5 == :failed + s4 = :failed + else + s4 = [] + while s5 != :failed + s4 << s5 + s5 = parse_nl + end + end + if s4 == :failed + @scanner.pos = s0 + s0 = :failed + else + @reported_pos = s0 + s0 = { 'k' => s1.join, 'v' => s3.join } + end else - @reported_pos = s0 - s0 = { "k" => s1.join, "v" => s3.join } + @scanner.pos = s0 + s0 = :failed end - else - @current_pos = s0 - s0 = :failed + s0 = parse_header_teban if s0 == :failed + s0 end - s0 = parse_header_teban if s0 == :failed - s0 - end - # header_teban : [先後上下] "手番" nl - def parse_header_teban - s0 = @current_pos - s1 = parse_turn - if s1 == :failed - @current_pos = s0 - :failed - else - s2 = match_str("手番") - if s2 == :failed - @current_pos = s0 + # header_teban : [先後上下] "手番" nl + def parse_header_teban + s0 = @scanner.pos + s1 = parse_turn + if s1 == :failed + @scanner.pos = s0 :failed else - s3 = parse_nl - if s3 == :failed - @current_pos = s0 + s2 = match_str('手番') + if s2 == :failed + @scanner.pos = s0 :failed else - @reported_pos = s0 - { "k" => "手番", "v" => s1 } + s3 = parse_nl + if s3 == :failed + @scanner.pos = s0 + :failed + else + @reported_pos = s0 + { 'k' => '手番', 'v' => s1 } + end end end end - end - # moves : firstboard : move* result? - def parse_moves - s0 = @current_pos - s1 = parse_firstboard - if s1 == :failed - @current_pos = s0 - s0 = :failed - else - s2 = [] - s3 = parse_move - while s3 != :failed - s2 << s3 + # moves : firstboard : move* result? + def parse_moves + s0 = @scanner.pos + s1 = parse_firstboard + if s1 == :failed + @scanner.pos = s0 + s0 = :failed + else + s2 = [] s3 = parse_move + while s3 != :failed + s2 << s3 + s3 = parse_move + end + s3 = parse_result + s3 = nil if s3 == :failed + @reported_pos = s0 + s0 = -> (hd, tl, res) do + tl.unshift(hd) + tl << { 'special' => res } if res && !tl[tl.length - 1]['special'] + tl + end.call(s1, s2, s3) end - s3 = parse_result - s3 = nil if s3 == :failed - @reported_pos = s0 - s0 = -> (hd, tl, res) do - tl.unshift(hd) - tl << { "special" => res } if res && !tl[tl.length - 1]["special"] - tl - end.call(s1, s2, s3) + s0 end - s0 - end - # firstboard : comment* pointer? - def parse_firstboard - s0 = @current_pos - s1 = [] - s2 = parse_comment - while s2 != :failed - s1 << s2 + # firstboard : comment* pointer? + def parse_firstboard + s0 = @scanner.pos + s1 = [] s2 = parse_comment + while s2 != :failed + s1 << s2 + s2 = parse_comment + end + parse_pointer + @reported_pos = s0 + s1.empty? ? {} : { 'comments' => s1 } end - parse_pointer - @reported_pos = s0 - s0 = s1.empty? ? {} : { "comments" => s1 } - s0 - end - # move : line comment* pointer? (nl | " ")* - def parse_move - s0 = @current_pos - s1 = parse_line - if s1 == :failed - @current_pos = s0 - s0 = :failed - else - s2 = [] - s3 = parse_comment - while s3 != :failed - s2 << s3 + # move : line comment* pointer? (nl | " ")* + def parse_move + s0 = @scanner.pos + s1 = parse_line + if s1 == :failed + @scanner.pos = s0 + s0 = :failed + else + s2 = [] s3 = parse_comment - end - parse_pointer - s4 = [] - s5 = parse_nl - s5 = match_space if s5 == :failed - while s5 != :failed - s4 << s5 + while s3 != :failed + s2 << s3 + s3 = parse_comment + end + parse_pointer + s4 = [] s5 = parse_nl s5 = match_space if s5 == :failed + while s5 != :failed + s4 << s5 + s5 = parse_nl + s5 = match_space if s5 == :failed + end + @reported_pos = s0 + s0 = -> (line, c) do + ret = { 'move' => line } + ret['comments'] = c unless c.empty? + ret + end.call(s1, s2) end - @reported_pos = s0 - s0 = -> (line, c) do - ret = { "move" => line } - ret["comments"] = c if !c.empty? - ret - end.call(s1, s2) + + s0 end - s0 - end - - # line : [▲△] fugou (nl / " ")* - def parse_line - s0 = @current_pos - s1 = match_regexp(/^[▲△]/) - if s1 == :failed - @current_pos = s0 - s0 = :failed - else - s1 = if s1 == "▲" - { "color" => 0 } - else - { "color" => 1 } - end - s2 = parse_fugou - if s2 == :failed - @current_pos = s0 + # line : [▲△] fugou (nl / " ")* + def parse_line + s0 = @scanner.pos + s1 = match_regexp(/[▲△]/) + if s1 == :failed + @scanner.pos = s0 s0 = :failed else - s3 = [] - s4 = parse_nl - s4 = match_space if s4 == :failed - while s4 != :failed - s3 << s4 + s1 = if s1 == '▲' + { 'color' => 0 } + else + { 'color' => 1 } + end + s2 = parse_fugou + if s2 == :failed + @scanner.pos = s0 + s0 = :failed + else + s3 = [] s4 = parse_nl s4 = match_space if s4 == :failed + while s4 != :failed + s3 << s4 + s4 = parse_nl + s4 = match_space if s4 == :failed + end + @reported_pos = s0 + s0 = s2.merge(s1) end - @reported_pos = s0 - s0 = s2.merge(s1) end + s0 end - s0 - end - # fugou : place piece soutai? dousa? ("成" | "不成")? "打"? - def parse_fugou - s0 = @current_pos - s1 = parse_place - if s1 == :failed - @current_pos = s0 - :failed - else - s2 = parse_piece - if s2 == :failed - @current_pos = s0 + # fugou : place piece soutai? dousa? ("成" | "不成")? "打"? + def parse_fugou + s0 = @scanner.pos + s1 = parse_place + if s1 == :failed + @scanner.pos = s0 :failed else - s3 = parse_soutai - s3 = nil if s3 == :failed - s4 = parse_dousa - s4 = nil if s4 == :failed - s5 = match_str("成") - s5 = match_str("不成") if s5 == :failed - s5 = nil if s5 == :failed - s6 = match_str("打") - s6 = nil if s6 == :failed - @reported_pos = s0 - transform_fugou(s1, s2, s3, s4, s5, s6) + s2 = parse_piece + if s2 == :failed + @scanner.pos = s0 + :failed + else + s3 = parse_soutai + s3 = nil if s3 == :failed + s4 = parse_dousa + s4 = nil if s4 == :failed + s5 = match_str('成') + s5 = match_str('不成') if s5 == :failed + s5 = nil if s5 == :failed + s6 = match_str('打') + s6 = nil if s6 == :failed + @reported_pos = s0 + transform_fugou(s1, s2, s3, s4, s5, s6) + end end end - end - # place : num numkan - def parse_place - s0 = @current_pos - s1 = parse_num - if s1 == :failed - @current_pos = s0 - s0 = :failed - else - s2 = parse_numkan - if s2 == :failed - @current_pos = s0 + # place : num numkan + def parse_place + s0 = @scanner.pos + s1 = parse_num + if s1 == :failed + @scanner.pos = s0 s0 = :failed else - @reported_pos = s0 - s0 = { "x" => s1, "y" => s2 } + s2 = parse_numkan + if s2 == :failed + @scanner.pos = s0 + s0 = :failed + else + @reported_pos = s0 + s0 = { 'x' => s1, 'y' => s2 } + end end - end - if s0 == :failed - s0 = @current_pos - if match_regexp("同") == :failed - @current_pos = s0 - s0 = :failed - else - match_str(" ") - @reported_pos = s0 - s0 = { "same" => true } + if s0 == :failed + s0 = @scanner.pos + if match_regexp('同') == :failed + @scanner.pos = s0 + s0 = :failed + else + match_str(' ') + @reported_pos = s0 + s0 = { 'same' => true } + end end + s0 end - s0 - end - # soutai : [左直右] - def parse_soutai - match_regexp(/^[左直右]/) - end + # soutai : [左直右] + def parse_soutai + match_regexp(/[左直右]/) + end - # dousa : [上寄引] - def parse_dousa - match_regexp(/^[上寄引]/) - end + # dousa : [上寄引] + def parse_dousa + match_regexp(/[上寄引]/) + end - # "*" nonls nl - def parse_comment - s0 = @current_pos - if match_str("*") == :failed - @current_pos = s0 - s0 = :failed - else - s2 = parse_nonls - if parse_nl == :failed - @current_pos = s0 + # "*" nonls nl + def parse_comment + s0 = @scanner.pos + if match_str('*') == :failed + @scanner.pos = s0 s0 = :failed else - @reported_pos = s0 - s0 = s2.join + s2 = parse_nonls + if parse_nl == :failed + @scanner.pos = s0 + s0 = :failed + else + @reported_pos = s0 + s0 = s2.join + end end + s0 end - s0 - end - # fork : "変化:" " "* [0-9]+ "手" nl moves - def parse_fork - s0 = @current_pos - if match_str("変化:") == :failed - @current_pos = s0 - s0 = :failed - else - match_spaces - s3 = match_digits! - if s3 == :failed - @current_pos = s0 + # fork : "変化:" " "* [0-9]+ "手" nl moves + def parse_fork + s0 = @scanner.pos + if match_str('変化:') == :failed + @scanner.pos = s0 s0 = :failed - elsif match_str("手") != :failed - if parse_nl == :failed - @current_pos = s0 + else + match_spaces + s3 = match_digits! + if s3 == :failed + @scanner.pos = s0 s0 = :failed - else - s6 = parse_moves - if s6 == :failed - @current_pos = s0 + elsif match_str('手') != :failed + if parse_nl == :failed + @scanner.pos = s0 s0 = :failed else - @reported_pos = s0 - s0 = { "te" => s3.join.to_i, "moves" => s6[1..-1] } + s6 = parse_moves + if s6 == :failed + @scanner.pos = s0 + s0 = :failed + else + @reported_pos = s0 + s0 = { 'te' => s3.join.to_i, 'moves' => s6[1..-1] } + end end + else + @scanner.pos = s0 + s0 = :failed end - else - @current_pos = s0 - s0 = :failed end + s0 end - s0 - end - # turn : [先後上下] - def parse_turn - match_regexp(/^[先後上下]/) - end + # turn : [先後上下] + def parse_turn + match_regexp(/[先後上下]/) + end - # transform to jkf - 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 != "OTHER" + # transform to jkf + 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 != 'OTHER' + end + transform_root_header_data(ret) if ret['initial'] && ret['initial']['data'] + transform_root_forks(forks, moves) + ret end - transform_root_header_data(ret) if ret["initial"] && ret["initial"]["data"] - transform_root_forks(forks, moves) - ret - end - # transfrom fugou to jkf - def transform_fugou(pl, pi, sou, dou, pro, da) - ret = { "piece" => pi } - if pl["same"] - ret["same"] = true - else - ret["to"] = pl + # transfrom fugou to jkf + def transform_fugou(pl, pi, sou, dou, pro, da) + ret = { 'piece' => pi } + if pl['same'] + ret['same'] = true + else + ret['to'] = pl + end + ret['promote'] = (pro == '成') if pro + if da + ret['relative'] = 'H' + else + rel = soutai2relative(sou) + dousa2relative(dou) + ret['relative'] = rel unless rel.empty? + end + ret end - ret["promote"] = (pro == "成") if pro - if da - ret["relative"] = "H" - else - rel = soutai2relative(sou) + dousa2relative(dou) - ret["relative"] = rel unless rel.empty? + + # relative string to jkf + def soutai2relative(str) + { + '左' => 'L', + '直' => 'C', + '右' => 'R' + }[str] || '' end - ret - end - # relative string to jkf - def soutai2relative(str) - { - "左" => "L", - "直" => "C", - "右" => "R" - }[str] || "" - end + # movement string to jkf + def dousa2relative(str) + { + '上' => 'U', + '寄' => 'M', + '引' => 'D' + }[str] || '' + end - # movement string to jkf - def dousa2relative(str) - { - "上" => "U", - "寄" => "M", - "引" => "D" - }[str] || "" - end + # generate motigoma + def make_hand(str) + ret = { 'FU' => 0, 'KY' => 0, 'KE' => 0, 'GI' => 0, 'KI' => 0, 'KA' => 0, 'HI' => 0 } + return ret if str.empty? - # generate motigoma - def make_hand(str) - ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 } - return ret if str.empty? + str.gsub(/ $/, '').split(' ').each do |kind| + next if kind.empty? + ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1]) + end - str.gsub(/ $/, "").split(" ").each do |kind| - next if kind.empty? - ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1]) + ret end - ret - end - - # check eos - def eos? - @input[@current_pos].nil? + def eos? + @scanner.eos? + end end end end